diff options
Diffstat (limited to 'src/or')
59 files changed, 2106 insertions, 1042 deletions
diff --git a/src/or/buffers.c b/src/or/buffers.c index 70f8b4a52..73127490c 100644 --- a/src/or/buffers.c +++ b/src/or/buffers.c @@ -588,7 +588,7 @@ buf_add_chunk_with_capacity(buf_t *buf, size_t capacity, int capped) * *<b>reached_eof</b> to 1. Return -1 on error, 0 on eof or blocking, * and the number of bytes read otherwise. */ static INLINE int -read_to_chunk(buf_t *buf, chunk_t *chunk, int fd, size_t at_most, +read_to_chunk(buf_t *buf, chunk_t *chunk, tor_socket_t fd, size_t at_most, int *reached_eof, int *socket_error) { ssize_t read_result; @@ -645,7 +645,7 @@ read_to_chunk_tls(buf_t *buf, chunk_t *chunk, tor_tls_t *tls, */ /* XXXX023 indicate "read blocked" somehow? */ int -read_to_buf(int s, size_t at_most, buf_t *buf, int *reached_eof, +read_to_buf(tor_socket_t s, size_t at_most, buf_t *buf, int *reached_eof, int *socket_error) { /* XXXX023 It's stupid to overload the return values for these functions: @@ -744,7 +744,7 @@ read_to_buf_tls(tor_tls_t *tls, size_t at_most, buf_t *buf) * written on success, 0 on blocking, -1 on failure. */ static INLINE int -flush_chunk(int s, buf_t *buf, chunk_t *chunk, size_t sz, +flush_chunk(tor_socket_t s, buf_t *buf, chunk_t *chunk, size_t sz, size_t *buf_flushlen) { ssize_t write_result; @@ -816,7 +816,7 @@ flush_chunk_tls(tor_tls_t *tls, buf_t *buf, chunk_t *chunk, * -1 on failure. Return 0 if write() would block. */ int -flush_buf(int s, buf_t *buf, size_t sz, size_t *buf_flushlen) +flush_buf(tor_socket_t s, buf_t *buf, size_t sz, size_t *buf_flushlen) { /* XXXX023 It's stupid to overload the return values for these functions: * "error status" and "number of bytes flushed" are not mutually exclusive. @@ -1459,7 +1459,7 @@ log_unsafe_socks_warning(int socks_protocol, const char *address, { static ratelim_t socks_ratelim = RATELIM_INIT(SOCKS_WARN_INTERVAL); - or_options_t *options = get_options(); + const or_options_t *options = get_options(); char *m = NULL; if (! options->WarnUnsafeSocks) return; @@ -2240,7 +2240,6 @@ write_to_evbuffer_zlib(struct evbuffer *buf, tor_zlib_state_t *state, int over = 0, n; struct evbuffer_iovec vec[1]; do { - int need_new_chunk = 0; { size_t cap = data_len / 4; if (cap < 128) @@ -2269,7 +2268,6 @@ write_to_evbuffer_zlib(struct evbuffer *buf, tor_zlib_state_t *state, if (avail) { /* Zlib says we need more room (ZLIB_BUF_FULL). Start a new chunk * automatically, whether were going to or not. */ - need_new_chunk = 1; } break; } diff --git a/src/or/buffers.h b/src/or/buffers.h index ef64bcce5..613001066 100644 --- a/src/or/buffers.h +++ b/src/or/buffers.h @@ -24,11 +24,11 @@ size_t buf_datalen(const buf_t *buf); size_t buf_allocation(const buf_t *buf); size_t buf_slack(const buf_t *buf); -int read_to_buf(int s, size_t at_most, buf_t *buf, int *reached_eof, +int read_to_buf(tor_socket_t s, size_t at_most, buf_t *buf, int *reached_eof, int *socket_error); int read_to_buf_tls(tor_tls_t *tls, size_t at_most, buf_t *buf); -int flush_buf(int s, buf_t *buf, size_t sz, size_t *buf_flushlen); +int flush_buf(tor_socket_t s, buf_t *buf, size_t sz, size_t *buf_flushlen); int flush_buf_tls(tor_tls_t *tls, buf_t *buf, size_t sz, size_t *buf_flushlen); int write_to_buf(const char *string, size_t string_len, buf_t *buf); diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c index d02ea1678..4ec45bc08 100644 --- a/src/or/circuitbuild.c +++ b/src/or/circuitbuild.c @@ -263,7 +263,7 @@ circuit_build_times_test_frequency(void) } /** - * Retrieve and bounds-check the cbtmintimeout consensus paramter. + * Retrieve and bounds-check the cbtmintimeout consensus parameter. * * Effect: This is the minimum allowed timeout value in milliseconds. * The minimum is to prevent rounding to 0 (we only check once @@ -679,7 +679,15 @@ circuit_build_times_shuffle_and_store_array(circuit_build_times_t *cbt, log_notice(LD_CIRC, "The number of circuit times that this Tor version " "uses to calculate build times is less than the number stored " "in your state file. Decreasing the circuit time history from " - "%d to %d.", num_times, CBT_NCIRCUITS_TO_OBSERVE); + "%lu to %d.", (unsigned long)num_times, + CBT_NCIRCUITS_TO_OBSERVE); + } + + if (n > INT_MAX-1) { + log_warn(LD_CIRC, "For some insane reasons, you had %lu circuit build " + "observations in your state file. That's far too many; probably " + "there's a bug here.", (unsigned long)n); + n = INT_MAX-1; } /* This code can only be run on a compact array */ @@ -1494,7 +1502,7 @@ get_unique_circ_id_by_conn(or_connection_t *conn) } /** If <b>verbose</b> is false, allocate and return a comma-separated list of - * the currently built elements of circuit_t. If <b>verbose</b> is true, also + * the currently built elements of <b>circ</b>. If <b>verbose</b> is true, also * list information about link status in a more verbose format using spaces. * If <b>verbose_names</b> is false, give nicknames for Named routers and hex * digests for others; if <b>verbose_names</b> is true, use $DIGEST=Name style @@ -1580,7 +1588,7 @@ circuit_list_path_impl(origin_circuit_t *circ, int verbose, int verbose_names) } /** If <b>verbose</b> is false, allocate and return a comma-separated - * list of the currently built elements of circuit_t. If + * list of the currently built elements of <b>circ</b>. If * <b>verbose</b> is true, also list information about link status in * a more verbose format using spaces. */ @@ -1591,7 +1599,7 @@ circuit_list_path(origin_circuit_t *circ, int verbose) } /** Allocate and return a comma-separated list of the currently built elements - * of circuit_t, giving each as a verbose nickname. + * of <b>circ</b>, giving each as a verbose nickname. */ char * circuit_list_path_for_controller(origin_circuit_t *circ) @@ -1600,7 +1608,7 @@ circuit_list_path_for_controller(origin_circuit_t *circ) } /** Log, at severity <b>severity</b>, the nicknames of each router in - * circ's cpath. Also log the length of the cpath, and the intended + * <b>circ</b>'s cpath. Also log the length of the cpath, and the intended * exit point. */ void @@ -1612,7 +1620,7 @@ circuit_log_path(int severity, unsigned int domain, origin_circuit_t *circ) } /** Tell the rep(utation)hist(ory) module about the status of the links - * in circ. Hops that have become OPEN are marked as successfully + * in <b>circ</b>. Hops that have become OPEN are marked as successfully * extended; the _first_ hop that isn't open (if any) is marked as * unable to extend. */ @@ -1748,10 +1756,9 @@ circuit_handle_first_hop(origin_circuit_t *circ) if (!n_conn) { /* not currently connected in a useful way. */ - const char *name = strlen(firsthop->extend_info->nickname) ? - firsthop->extend_info->nickname : fmt_addr(&firsthop->extend_info->addr); - log_info(LD_CIRC, "Next router is %s: %s ", - safe_str_client(name), msg?msg:"???"); + log_info(LD_CIRC, "Next router is %s: %s", + safe_str_client(extend_info_describe(firsthop->extend_info)), + msg?msg:"???"); circ->_base.n_hop = extend_info_dup(firsthop->extend_info); if (should_launch) { @@ -1818,7 +1825,7 @@ circuit_n_conn_done(or_connection_t *or_conn, int status) continue; } else { /* We expected a key. See if it's the right one. */ - if (memcmp(or_conn->identity_digest, + if (tor_memneq(or_conn->identity_digest, circ->n_hop->identity_digest, DIGEST_LEN)) continue; } @@ -1941,7 +1948,7 @@ inform_testing_reachability(void) static INLINE int should_use_create_fast_for_circuit(origin_circuit_t *circ) { - or_options_t *options = get_options(); + const or_options_t *options = get_options(); tor_assert(circ->cpath); tor_assert(circ->cpath->extend_info); @@ -2034,7 +2041,7 @@ circuit_send_next_onion_skin(origin_circuit_t *circ) circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_BUILDING); log_info(LD_CIRC,"First hop: finished sending %s cell to '%s'", fast ? "CREATE_FAST" : "CREATE", - node ? node_get_nickname(node) : "<unnamed>"); + node ? node_describe(node) : "<unnamed>"); } else { tor_assert(circ->cpath->state == CPATH_STATE_OPEN); tor_assert(circ->_base.state == CIRCUIT_STATE_BUILDING); @@ -2076,7 +2083,7 @@ circuit_send_next_onion_skin(origin_circuit_t *circ) if (circ->build_state->onehop_tunnel) control_event_bootstrap(BOOTSTRAP_STATUS_REQUESTING_STATUS, 0); if (!can_complete_circuit && !circ->build_state->onehop_tunnel) { - or_options_t *options = get_options(); + const or_options_t *options = get_options(); can_complete_circuit=1; /* FFFF Log a count of known routers here */ log_notice(LD_GENERAL, @@ -2226,7 +2233,7 @@ circuit_extend(cell_t *cell, circuit_t *circ) /* Next, check if we're being asked to connect to the hop that the * extend cell came from. There isn't any reason for that, and it can * assist circular-path attacks. */ - if (!memcmp(id_digest, TO_OR_CIRCUIT(circ)->p_conn->identity_digest, + if (tor_memeq(id_digest, TO_OR_CIRCUIT(circ)->p_conn->identity_digest, DIGEST_LEN)) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Client asked me to extend back to the previous hop."); @@ -2643,7 +2650,7 @@ choose_good_exit_server_general(int need_uptime, int need_capacity) smartlist_t *connections; int best_support = -1; int n_best_support=0; - or_options_t *options = get_options(); + const or_options_t *options = get_options(); const smartlist_t *the_nodes; const node_t *node=NULL; @@ -2818,7 +2825,7 @@ choose_good_exit_server_general(int need_uptime, int need_capacity) tor_free(n_supported); if (node) { - log_info(LD_CIRC, "Chose exit server '%s'", node_get_nickname(node)); + log_info(LD_CIRC, "Chose exit server '%s'", node_describe(node)); return node; } if (options->ExitNodes) { @@ -2844,7 +2851,7 @@ static const node_t * choose_good_exit_server(uint8_t purpose, int need_uptime, int need_capacity, int is_internal) { - or_options_t *options = get_options(); + const or_options_t *options = get_options(); router_crn_flags_t flags = CRN_NEED_DESC; if (need_uptime) flags |= CRN_NEED_UPTIME; @@ -2874,7 +2881,7 @@ choose_good_exit_server(uint8_t purpose, static void warn_if_last_router_excluded(origin_circuit_t *circ, const extend_info_t *exit) { - or_options_t *options = get_options(); + const or_options_t *options = get_options(); routerset_t *rs = options->ExcludeNodes; const char *description; uint8_t purpose = circ->_base.purpose; @@ -2925,7 +2932,7 @@ warn_if_last_router_excluded(origin_circuit_t *circ, const extend_info_t *exit) log_warn(LD_BUG, "Using %s '%s' which is listed in ExcludeNodes%s, " "even though StrictNodes is set. Please report. " "(Circuit purpose: %s)", - description, exit->nickname, + description, extend_info_describe(exit), rs==options->ExcludeNodes?"":" or ExcludeExitNodes", circuit_purpose_to_string(purpose)); } else { @@ -2934,7 +2941,7 @@ warn_if_last_router_excluded(origin_circuit_t *circ, const extend_info_t *exit) "prevent this (and possibly break your Tor functionality), " "set the StrictNodes configuration option. " "(Circuit purpose: %s)", - description, exit->nickname, + description, extend_info_describe(exit), rs==options->ExcludeNodes?"":" or ExcludeExitNodes", circuit_purpose_to_string(purpose)); } @@ -2964,7 +2971,8 @@ onion_pick_cpath_exit(origin_circuit_t *circ, extend_info_t *exit) if (exit) { /* the circuit-builder pre-requested one */ warn_if_last_router_excluded(circ, exit); - log_info(LD_CIRC,"Using requested exit node '%s'", exit->nickname); + log_info(LD_CIRC,"Using requested exit node '%s'", + extend_info_describe(exit)); exit = extend_info_dup(exit); } else { /* we have to decide one */ const node_t *node = @@ -3014,8 +3022,8 @@ circuit_extend_to_new_exit(origin_circuit_t *circ, extend_info_t *exit) circuit_append_new_exit(circ, exit); circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_BUILDING); if ((err_reason = circuit_send_next_onion_skin(circ))<0) { - log_warn(LD_CIRC, "Couldn't extend circuit to new point '%s'.", - exit->nickname); + log_warn(LD_CIRC, "Couldn't extend circuit to new point %s.", + extend_info_describe(exit)); circuit_mark_for_close(TO_CIRCUIT(circ), -err_reason); return -1; } @@ -3087,7 +3095,7 @@ choose_good_middle_server(uint8_t purpose, const node_t *r, *choice; crypt_path_t *cpath; smartlist_t *excluded; - or_options_t *options = get_options(); + const or_options_t *options = get_options(); router_crn_flags_t flags = CRN_NEED_DESC; tor_assert(_CIRCUIT_PURPOSE_MIN <= purpose && purpose <= _CIRCUIT_PURPOSE_MAX); @@ -3129,7 +3137,7 @@ choose_good_entry_server(uint8_t purpose, cpath_build_state_t *state) { const node_t *choice; smartlist_t *excluded; - or_options_t *options = get_options(); + const or_options_t *options = get_options(); router_crn_flags_t flags = CRN_NEED_GUARD|CRN_NEED_DESC; const node_t *node; @@ -3239,7 +3247,8 @@ onion_extend_cpath(origin_circuit_t *circ) } log_debug(LD_CIRC,"Chose router %s for hop %d (exit is %s)", - info->nickname, cur_len+1, build_state_get_exit_nickname(state)); + extend_info_describe(info), + cur_len+1, build_state_get_exit_nickname(state)); onion_append_hop(&circ->cpath, info); extend_info_free(info); @@ -3379,7 +3388,8 @@ build_state_get_exit_nickname(cpath_build_state_t *state) */ static int entry_guard_set_status(entry_guard_t *e, const node_t *node, - time_t now, or_options_t *options, const char **reason) + time_t now, const or_options_t *options, + const char **reason) { char buf[HEX_DIGEST_LEN+1]; int changed = 0; @@ -3394,6 +3404,8 @@ entry_guard_set_status(entry_guard_t *e, const node_t *node, else if (options->UseBridges && (!node->ri || node->ri->purpose != ROUTER_PURPOSE_BRIDGE)) *reason = "not a bridge"; + else if (options->UseBridges && !node_is_a_configured_bridge(node)) + *reason = "not a configured bridge"; else if (!options->UseBridges && !node->is_possible_guard && !routerset_contains_node(options->EntryNodes,node)) *reason = "not recommended as a guard"; @@ -3460,7 +3472,7 @@ entry_is_live(entry_guard_t *e, int need_uptime, int need_capacity, int assume_reachable, const char **msg) { const node_t *node; - or_options_t *options = get_options(); + const or_options_t *options = get_options(); tor_assert(msg); if (e->bad_since) { @@ -3483,6 +3495,10 @@ entry_is_live(entry_guard_t *e, int need_uptime, int need_capacity, *msg = "not a bridge"; return NULL; } + if (!node_is_a_configured_bridge(node)) { + *msg = "not a configured bridge"; + return NULL; + } } else { /* !get_options()->UseBridges */ if (node_get_purpose(node) != ROUTER_PURPOSE_GENERAL) { *msg = "not general-purpose"; @@ -3527,7 +3543,7 @@ static INLINE entry_guard_t * is_an_entry_guard(const char *digest) { SMARTLIST_FOREACH(entry_guards, entry_guard_t *, entry, - if (!memcmp(digest, entry->identity, DIGEST_LEN)) + if (tor_memeq(digest, entry->identity, DIGEST_LEN)) return entry; ); return NULL; @@ -3541,20 +3557,24 @@ log_entry_guards(int severity) smartlist_t *elements = smartlist_create(); char *s; - SMARTLIST_FOREACH(entry_guards, entry_guard_t *, e, + SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, e) { const char *msg = NULL; char *cp; if (entry_is_live(e, 0, 1, 0, &msg)) - tor_asprintf(&cp, "%s (up %s)", + tor_asprintf(&cp, "%s [%s] (up %s)", e->nickname, + hex_str(e->identity, DIGEST_LEN), e->made_contact ? "made-contact" : "never-contacted"); else - tor_asprintf(&cp, "%s (%s, %s)", - e->nickname, msg, + tor_asprintf(&cp, "%s [%s] (%s, %s)", + e->nickname, + hex_str(e->identity, DIGEST_LEN), + msg, e->made_contact ? "made-contact" : "never-contacted"); smartlist_add(elements, cp); - }); + } + SMARTLIST_FOREACH_END(e); s = smartlist_join_strings(elements, ",", 0, NULL); SMARTLIST_FOREACH(elements, char*, cp, tor_free(cp)); @@ -3578,7 +3598,7 @@ control_event_guard_deferred(void) #if 0 int n = 0; const char *msg; - or_options_t *options = get_options(); + const or_options_t *options = get_options(); if (!entry_guards) return; SMARTLIST_FOREACH(entry_guards, entry_guard_t *, entry, @@ -3622,8 +3642,8 @@ add_an_entry_guard(const node_t *chosen, int reset_status) return NULL; } entry = tor_malloc_zero(sizeof(entry_guard_t)); - log_info(LD_CIRC, "Chose '%s' as new entry guard.", - node_get_nickname(node)); + log_info(LD_CIRC, "Chose %s as new entry guard.", + node_describe(node)); strlcpy(entry->nickname, node_get_nickname(node), sizeof(entry->nickname)); memcpy(entry->identity, node->identity, DIGEST_LEN); /* Choose expiry time smudged over the past month. The goal here @@ -3646,7 +3666,7 @@ add_an_entry_guard(const node_t *chosen, int reset_status) /** If the use of entry guards is configured, choose more entry guards * until we have enough in the list. */ static void -pick_entry_guards(or_options_t *options) +pick_entry_guards(const or_options_t *options) { int changed = 0; @@ -3779,10 +3799,9 @@ remove_dead_entry_guards(time_t now) * think that things are unlisted. */ void -entry_guards_compute_status(or_options_t *options, time_t now) +entry_guards_compute_status(const or_options_t *options, time_t now) { int changed = 0; - int severity = LOG_DEBUG; digestmap_t *reasons; if (! entry_guards) @@ -3809,15 +3828,14 @@ entry_guards_compute_status(or_options_t *options, time_t now) if (remove_dead_entry_guards(now)) changed = 1; - severity = changed ? LOG_DEBUG : LOG_INFO; - if (changed) { SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, entry) { const char *reason = digestmap_get(reasons, entry->identity); const char *live_msg = ""; const node_t *r = entry_is_live(entry, 0, 1, 0, &live_msg); - log_info(LD_CIRC, "Summary: Entry '%s' is %s, %s%s%s, and %s%s.", + log_info(LD_CIRC, "Summary: Entry %s [%s] is %s, %s%s%s, and %s%s.", entry->nickname, + hex_str(entry->identity, DIGEST_LEN), entry->unreachable_since ? "unreachable" : "reachable", entry->bad_since ? "unusable" : "usable", reason ? ", ": "", @@ -3860,7 +3878,7 @@ entry_guard_register_connect_status(const char *digest, int succeeded, SMARTLIST_FOREACH(entry_guards, entry_guard_t *, e, { - if (!memcmp(e->identity, digest, DIGEST_LEN)) { + if (tor_memeq(e->identity, digest, DIGEST_LEN)) { entry = e; idx = e_sl_idx; break; @@ -3971,7 +3989,7 @@ entry_nodes_should_be_added(void) /** Add all nodes in EntryNodes that aren't currently guard nodes to the list * of guard nodes, at the front. */ static void -entry_guards_prepend_from_config(or_options_t *options) +entry_guards_prepend_from_config(const or_options_t *options) { smartlist_t *entry_nodes, *entry_fps; smartlist_t *old_entry_guards_on_list, *old_entry_guards_not_on_list; @@ -4050,7 +4068,7 @@ entry_guards_prepend_from_config(or_options_t *options) * list already and we must stick to it. */ int -entry_list_is_constrained(or_options_t *options) +entry_list_is_constrained(const or_options_t *options) { if (options->EntryNodes) return 1; @@ -4067,7 +4085,7 @@ entry_list_is_constrained(or_options_t *options) const node_t * choose_random_entry(cpath_build_state_t *state) { - or_options_t *options = get_options(); + const or_options_t *options = get_options(); smartlist_t *live_entry_guards = smartlist_create(); smartlist_t *exit_family = smartlist_create(); const node_t *chosen_exit = @@ -4488,6 +4506,9 @@ typedef struct { tor_addr_t addr; /** TLS port for the bridge. */ uint16_t port; + /** Boolean: We are re-parsing our bridge list, and we are going to remove + * this one if we don't find it in the list of configured bridges. */ + unsigned marked_for_removal : 1; /** Expected identity digest, or all zero bytes if we don't know what the * digest should be. */ char identity[DIGEST_LEN]; @@ -4496,11 +4517,39 @@ typedef struct { } bridge_info_t; /** A list of configured bridges. Whenever we actually get a descriptor - * for one, we add it as an entry guard. */ + * for one, we add it as an entry guard. Note that the order of bridges + * in this list does not necessarily correspond to the order of bridges + * in the torrc. */ static smartlist_t *bridge_list = NULL; -/** Initialize the bridge list to empty, creating it if needed. */ +/** Mark every entry of the bridge list to be removed on our next call to + * sweep_bridge_list unless it has first been un-marked. */ void +mark_bridge_list(void) +{ + if (!bridge_list) + bridge_list = smartlist_create(); + SMARTLIST_FOREACH(bridge_list, bridge_info_t *, b, + b->marked_for_removal = 1); +} + +/** Remove every entry of the bridge list that was marked with + * mark_bridge_list if it has not subsequently been un-marked. */ +void +sweep_bridge_list(void) +{ + if (!bridge_list) + bridge_list = smartlist_create(); + SMARTLIST_FOREACH_BEGIN(bridge_list, bridge_info_t *, b) { + if (b->marked_for_removal) { + SMARTLIST_DEL_CURRENT(bridge_list, b); + tor_free(b); + } + } SMARTLIST_FOREACH_END(b); +} + +/** Initialize the bridge list to empty, creating it if needed. */ +static void clear_bridge_list(void) { if (!bridge_list) @@ -4513,7 +4562,8 @@ clear_bridge_list(void) * (either by comparing keys if possible, else by comparing addr/port). * Else return NULL. */ static bridge_info_t * -get_configured_bridge_by_addr_port_digest(tor_addr_t *addr, uint16_t port, +get_configured_bridge_by_addr_port_digest(const tor_addr_t *addr, + uint16_t port, const char *digest) { if (!bridge_list) @@ -4524,7 +4574,7 @@ get_configured_bridge_by_addr_port_digest(tor_addr_t *addr, uint16_t port, !tor_addr_compare(&bridge->addr, addr, CMP_EXACT) && bridge->port == port) return bridge; - if (!memcmp(bridge->identity, digest, DIGEST_LEN)) + if (digest && tor_memeq(bridge->identity, digest, DIGEST_LEN)) return bridge; } SMARTLIST_FOREACH_END(bridge); @@ -4549,12 +4599,31 @@ routerinfo_is_a_configured_bridge(const routerinfo_t *ri) return get_configured_bridge_by_routerinfo(ri) ? 1 : 0; } +/** Return 1 if <b>node</b> is one of our configured bridges, else 0. */ +int +node_is_a_configured_bridge(const node_t *node) +{ + tor_addr_t addr; + uint16_t orport; + if (!node) + return 0; + if (node_get_addr(node, &addr) < 0) + return 0; + orport = node_get_orport(node); + if (orport == 0) + return 0; + + return get_configured_bridge_by_addr_port_digest( + &addr, orport, node->identity) != NULL; +} + /** We made a connection to a router at <b>addr</b>:<b>port</b> * without knowing its digest. Its digest turned out to be <b>digest</b>. * If it was a bridge, and we still don't know its digest, record it. */ void -learned_router_identity(tor_addr_t *addr, uint16_t port, const char *digest) +learned_router_identity(const tor_addr_t *addr, uint16_t port, + const char *digest) { bridge_info_t *bridge = get_configured_bridge_by_addr_port_digest(addr, port, digest); @@ -4566,11 +4635,20 @@ learned_router_identity(tor_addr_t *addr, uint16_t port, const char *digest) } /** Remember a new bridge at <b>addr</b>:<b>port</b>. If <b>digest</b> - * is set, it tells us the identity key too. */ + * is set, it tells us the identity key too. If we already had the + * bridge in our list, unmark it, and don't actually add anything new. */ void -bridge_add_from_config(const tor_addr_t *addr, uint16_t port, char *digest) +bridge_add_from_config(const tor_addr_t *addr, uint16_t port, + const char *digest) { - bridge_info_t *b = tor_malloc_zero(sizeof(bridge_info_t)); + bridge_info_t *b; + + if ((b = get_configured_bridge_by_addr_port_digest(addr, port, digest))) { + b->marked_for_removal = 0; + return; + } + + b = tor_malloc_zero(sizeof(bridge_info_t)); tor_addr_copy(&b->addr, addr); b->port = port; if (digest) @@ -4578,6 +4656,7 @@ bridge_add_from_config(const tor_addr_t *addr, uint16_t port, char *digest) b->fetch_status.schedule = DL_SCHED_BRIDGE; if (!bridge_list) bridge_list = smartlist_create(); + smartlist_add(bridge_list, b); } @@ -4605,7 +4684,7 @@ find_bridge_by_digest(const char *digest) { SMARTLIST_FOREACH(bridge_list, bridge_info_t *, bridge, { - if (!memcmp(bridge->identity, digest, DIGEST_LEN)) + if (tor_memeq(bridge->identity, digest, DIGEST_LEN)) return bridge; }); return NULL; @@ -4616,7 +4695,7 @@ static void launch_direct_bridge_descriptor_fetch(bridge_info_t *bridge) { char *address; - or_options_t *options = get_options(); + const or_options_t *options = get_options(); if (connection_get_by_type_addr_port_purpose( CONN_TYPE_DIR, &bridge->addr, bridge->port, @@ -4657,7 +4736,7 @@ retry_bridge_descriptor_fetch_directly(const char *digest) * descriptor, fetch a new copy of its descriptor -- either directly * from the bridge or via a bridge authority. */ void -fetch_bridge_descriptors(or_options_t *options, time_t now) +fetch_bridge_descriptors(const or_options_t *options, time_t now) { int num_bridge_auths = get_n_authorities(BRIDGE_DIRINFO); int ask_bridge_directly; @@ -4851,7 +4930,7 @@ any_pending_bridge_descriptor_fetches(void) * down. Else return 0. If <b>act</b> is 1, then mark the down guards * up; else just observe and report. */ static int -entries_retry_helper(or_options_t *options, int act) +entries_retry_helper(const or_options_t *options, int act) { const node_t *node; int any_known = 0; @@ -4890,7 +4969,7 @@ entries_retry_helper(or_options_t *options, int act) /** Do we know any descriptors for our bridges / entrynodes, and are * all the ones we have descriptors for down? */ int -entries_known_but_down(or_options_t *options) +entries_known_but_down(const or_options_t *options) { tor_assert(entry_list_is_constrained(options)); return entries_retry_helper(options, 0); @@ -4898,7 +4977,7 @@ entries_known_but_down(or_options_t *options) /** Mark all down known bridges / entrynodes up. */ void -entries_retry_all(or_options_t *options) +entries_retry_all(const or_options_t *options) { tor_assert(entry_list_is_constrained(options)); entries_retry_helper(options, 1); diff --git a/src/or/circuitbuild.h b/src/or/circuitbuild.h index 33d483df8..caa8a6738 100644 --- a/src/or/circuitbuild.h +++ b/src/or/circuitbuild.h @@ -51,11 +51,11 @@ void extend_info_free(extend_info_t *info); const node_t *build_state_get_exit_node(cpath_build_state_t *state); const char *build_state_get_exit_nickname(cpath_build_state_t *state); -void entry_guards_compute_status(or_options_t *options, time_t now); +void entry_guards_compute_status(const or_options_t *options, time_t now); int entry_guard_register_connect_status(const char *digest, int succeeded, int mark_relay_status, time_t now); void entry_nodes_should_be_added(void); -int entry_list_is_constrained(or_options_t *options); +int entry_list_is_constrained(const or_options_t *options); const node_t *choose_random_entry(cpath_build_state_t *state); int entry_guards_parse_state(or_state_t *state, int set, char **msg); void entry_guards_update_state(or_state_t *state); @@ -63,19 +63,21 @@ int getinfo_helper_entry_guards(control_connection_t *conn, const char *question, char **answer, const char **errmsg); -void clear_bridge_list(void); +void mark_bridge_list(void); +void sweep_bridge_list(void); int routerinfo_is_a_configured_bridge(const routerinfo_t *ri); -void learned_router_identity(tor_addr_t *addr, uint16_t port, +int node_is_a_configured_bridge(const node_t *node); +void learned_router_identity(const tor_addr_t *addr, uint16_t port, const char *digest); void bridge_add_from_config(const tor_addr_t *addr, uint16_t port, - char *digest); + const char *digest); void retry_bridge_descriptor_fetch_directly(const char *digest); -void fetch_bridge_descriptors(or_options_t *options, time_t now); +void fetch_bridge_descriptors(const or_options_t *options, time_t now); void learned_bridge_descriptor(routerinfo_t *ri, int from_cache); int any_bridge_descriptors_known(void); int any_pending_bridge_descriptor_fetches(void); -int entries_known_but_down(or_options_t *options); -void entries_retry_all(or_options_t *options); +int entries_known_but_down(const or_options_t *options); +void entries_retry_all(const or_options_t *options); void entry_guards_free_all(void); diff --git a/src/or/circuitlist.c b/src/or/circuitlist.c index 0aadcbfa0..93f5fd349 100644 --- a/src/or/circuitlist.c +++ b/src/or/circuitlist.c @@ -254,7 +254,7 @@ circuit_get_all_pending_on_or_conn(smartlist_t *out, or_connection_t *or_conn) continue; } else { /* We expected a key. See if it's the right one. */ - if (memcmp(or_conn->identity_digest, + if (tor_memneq(or_conn->identity_digest, circ->n_hop->identity_digest, DIGEST_LEN)) continue; } @@ -272,8 +272,10 @@ circuit_count_pending_on_or_conn(or_connection_t *or_conn) circuit_get_all_pending_on_or_conn(sl, or_conn); cnt = smartlist_len(sl); smartlist_free(sl); - log_debug(LD_CIRC,"or_conn to %s, %d pending circs", - or_conn->nickname ? or_conn->nickname : "NULL", cnt); + log_debug(LD_CIRC,"or_conn to %s at %s, %d pending circs", + or_conn->nickname ? or_conn->nickname : "NULL", + or_conn->_base.address, + cnt); return cnt; } @@ -717,7 +719,7 @@ circuit_dump_by_conn(connection_t *conn, int severity) tor_addr_eq(&circ->n_hop->addr, &conn->addr) && circ->n_hop->port == conn->port && conn->type == CONN_TYPE_OR && - !memcmp(TO_OR_CONN(conn)->identity_digest, + tor_memeq(TO_OR_CONN(conn)->identity_digest, circ->n_hop->identity_digest, DIGEST_LEN)) { circuit_dump_details(severity, circ, conn->conn_array_index, (circ->state == CIRCUIT_STATE_OPEN && @@ -771,8 +773,8 @@ circuit_get_by_circid_orconn_impl(circid_t circ_id, or_connection_t *conn) return found->circuit; return NULL; - /* The rest of this checks for bugs. Disabled by default. */ + /* We comment it out because coverity complains otherwise. { circuit_t *circ; for (circ=global_circuitlist;circ;circ = circ->next) { @@ -791,7 +793,7 @@ circuit_get_by_circid_orconn_impl(circid_t circ_id, or_connection_t *conn) } } return NULL; - } + } */ } /** Return a circ such that: @@ -862,7 +864,7 @@ circuit_unlink_all_from_or_conn(or_connection_t *conn, int reason) } /** Return a circ such that: - * - circ-\>rend_data-\>query is equal to <b>rend_query</b>, and + * - circ-\>rend_data-\>onion_address is equal to <b>rend_query</b>, and * - circ-\>purpose is equal to <b>purpose</b>. * * Return NULL if no such circuit exists. @@ -911,7 +913,7 @@ circuit_get_next_by_pk_and_purpose(origin_circuit_t *start, if (!digest) return TO_ORIGIN_CIRCUIT(circ); else if (TO_ORIGIN_CIRCUIT(circ)->rend_data && - !memcmp(TO_ORIGIN_CIRCUIT(circ)->rend_data->rend_pk_digest, + tor_memeq(TO_ORIGIN_CIRCUIT(circ)->rend_data->rend_pk_digest, digest, DIGEST_LEN)) return TO_ORIGIN_CIRCUIT(circ); } @@ -929,7 +931,7 @@ circuit_get_by_rend_token_and_purpose(uint8_t purpose, const char *token, for (circ = global_circuitlist; circ; circ = circ->next) { if (! circ->marked_for_close && circ->purpose == purpose && - ! memcmp(TO_OR_CIRCUIT(circ)->rend_token, token, len)) + tor_memeq(TO_OR_CIRCUIT(circ)->rend_token, token, len)) return TO_OR_CIRCUIT(circ); } return NULL; @@ -977,7 +979,7 @@ circuit_find_to_cannibalize(uint8_t purpose, extend_info_t *info, int need_uptime = (flags & CIRCLAUNCH_NEED_UPTIME) != 0; int need_capacity = (flags & CIRCLAUNCH_NEED_CAPACITY) != 0; int internal = (flags & CIRCLAUNCH_IS_INTERNAL) != 0; - or_options_t *options = get_options(); + const or_options_t *options = get_options(); /* Make sure we're not trying to create a onehop circ by * cannibalization. */ @@ -1006,7 +1008,7 @@ circuit_find_to_cannibalize(uint8_t purpose, extend_info_t *info, const node_t *ri1 = node_get_by_id(info->identity_digest); do { const node_t *ri2; - if (!memcmp(hop->extend_info->identity_digest, + if (tor_memeq(hop->extend_info->identity_digest, info->identity_digest, DIGEST_LEN)) goto next; if (ri1 && @@ -1096,7 +1098,7 @@ void circuit_expire_all_dirty_circs(void) { circuit_t *circ; - or_options_t *options = get_options(); + const or_options_t *options = get_options(); for (circ=global_circuitlist; circ; circ = circ->next) { if (CIRCUIT_IS_ORIGIN(circ) && diff --git a/src/or/circuituse.c b/src/or/circuituse.c index 135aa803a..67677ef05 100644 --- a/src/or/circuituse.c +++ b/src/or/circuituse.c @@ -74,7 +74,8 @@ circuit_is_acceptable(circuit_t *circ, edge_connection_t *conn, return 0; } - if (purpose == CIRCUIT_PURPOSE_C_GENERAL) + if (purpose == CIRCUIT_PURPOSE_C_GENERAL || + purpose == CIRCUIT_PURPOSE_C_REND_JOINED) if (circ->timestamp_dirty && circ->timestamp_dirty+get_options()->MaxCircuitDirtiness <= now) return 0; @@ -109,7 +110,7 @@ circuit_is_acceptable(circuit_t *circ, edge_connection_t *conn, char digest[DIGEST_LEN]; if (hexdigest_to_digest(conn->chosen_exit_name, digest) < 0) return 0; /* broken digest, we don't want it */ - if (memcmp(digest, build_state->chosen_exit->identity_digest, + if (tor_memneq(digest, build_state->chosen_exit->identity_digest, DIGEST_LEN)) return 0; /* this is a circuit to somewhere else */ if (tor_digest_is_zero(digest)) { @@ -289,7 +290,6 @@ circuit_expire_building(void) struct timeval general_cutoff, begindir_cutoff, fourhop_cutoff, cannibalize_cutoff, close_cutoff, extremely_old_cutoff; struct timeval now; - struct timeval introcirc_cutoff; cpath_build_state_t *build_state; tor_gettimeofday(&now); @@ -308,8 +308,6 @@ circuit_expire_building(void) SET_CUTOFF(close_cutoff, circ_times.close_ms); SET_CUTOFF(extremely_old_cutoff, circ_times.close_ms*2 + 1000); - introcirc_cutoff = begindir_cutoff; - while (next_circ) { struct timeval cutoff; victim = next_circ; @@ -326,8 +324,6 @@ circuit_expire_building(void) cutoff = fourhop_cutoff; else if (TO_ORIGIN_CIRCUIT(victim)->has_opened) cutoff = cannibalize_cutoff; - else if (victim->purpose == CIRCUIT_PURPOSE_C_INTRODUCING) - cutoff = introcirc_cutoff; else if (victim->purpose == CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT) cutoff = close_cutoff; else @@ -338,12 +334,6 @@ circuit_expire_building(void) #if 0 /* some debug logs, to help track bugs */ - if (victim->purpose == CIRCUIT_PURPOSE_C_INTRODUCING && - victim->timestamp_created.tv_sec <= introcirc_cutoff && - victim->timestamp_created.tv_sec > general_cutoff) - log_info(LD_REND|LD_CIRC, "Timing out introduction circuit which we " - "would not have done if it had been a general circuit."); - if (victim->purpose >= CIRCUIT_PURPOSE_C_INTRODUCING && victim->purpose <= CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED) { if (!victim->timestamp_dirty) @@ -646,7 +636,7 @@ void circuit_build_needed_circs(time_t now) { static time_t time_to_new_circuit = 0; - or_options_t *options = get_options(); + const or_options_t *options = get_options(); /* launch a new circ for any pending streams that need one */ connection_ap_attach_pending(); @@ -1218,7 +1208,7 @@ circuit_get_open_circ_or_launch(edge_connection_t *conn, int check_exit_policy; int need_uptime, need_internal; int want_onehop; - or_options_t *options = get_options(); + const or_options_t *options = get_options(); tor_assert(conn); tor_assert(circp); @@ -1328,8 +1318,8 @@ circuit_get_open_circ_or_launch(edge_connection_t *conn, conn->_base.state = AP_CONN_STATE_RENDDESC_WAIT; return 0; } - log_info(LD_REND,"Chose '%s' as intro point for '%s'.", - extend_info->nickname, + log_info(LD_REND,"Chose %s as intro point for '%s'.", + extend_info_describe(extend_info), safe_str_client(conn->rend_data->onion_address)); } @@ -1409,7 +1399,7 @@ circuit_get_open_circ_or_launch(edge_connection_t *conn, * a bad sign: we should tell the user. */ if (conn->num_circuits_launched < NUM_CIRCUITS_LAUNCHED_THRESHOLD && ++conn->num_circuits_launched == NUM_CIRCUITS_LAUNCHED_THRESHOLD) - log_warn(LD_BUG, "The application request to %s:%d has launched " + log_info(LD_CIRC, "The application request to %s:%d has launched " "%d circuits without finding one it likes.", escaped_safe_str_client(conn->socks_request->address), conn->socks_request->port, @@ -1478,15 +1468,35 @@ link_apconn_to_circ(edge_connection_t *apconn, origin_circuit_t *circ, } } -/** If an exit wasn't specifically chosen, save the history for future - * use. */ +/** Return true iff <b>address</b> is matched by one of the entries in + * TrackHostExits. */ +int +hostname_in_track_host_exits(const or_options_t *options, const char *address) +{ + if (!options->TrackHostExits) + return 0; + SMARTLIST_FOREACH_BEGIN(options->TrackHostExits, const char *, cp) { + if (cp[0] == '.') { /* match end */ + if (cp[1] == '\0' || + !strcasecmpend(address, cp) || + !strcasecmp(address, &cp[1])) + return 1; + } else if (strcasecmp(cp, address) == 0) { + return 1; + } + } SMARTLIST_FOREACH_END(cp); + return 0; +} + +/** If an exit wasn't explicitly specified for <b>conn</b>, consider saving + * the exit that we *did* choose for use by future connections to + * <b>conn</b>'s destination. + */ static void consider_recording_trackhost(edge_connection_t *conn, origin_circuit_t *circ) { - int found_needle = 0; - or_options_t *options = get_options(); - size_t len; - char *new_address; + const or_options_t *options = get_options(); + char *new_address = NULL; char fp[HEX_DIGEST_LEN+1]; /* Search the addressmap for this conn's destination. */ @@ -1496,18 +1506,8 @@ consider_recording_trackhost(edge_connection_t *conn, origin_circuit_t *circ) options->TrackHostExitsExpire)) return; /* nothing to track, or already mapped */ - SMARTLIST_FOREACH(options->TrackHostExits, const char *, cp, { - if (cp[0] == '.') { /* match end */ - if (cp[1] == '\0' || - !strcasecmpend(conn->socks_request->address, cp) || - !strcasecmp(conn->socks_request->address, &cp[1])) - found_needle = 1; - } else if (strcasecmp(cp, conn->socks_request->address) == 0) { - found_needle = 1; - } - }); - - if (!found_needle || !circ->build_state->chosen_exit) + if (!hostname_in_track_host_exits(options, conn->socks_request->address) || + !circ->build_state->chosen_exit) return; /* write down the fingerprint of the chosen exit, not the nickname, @@ -1516,12 +1516,7 @@ consider_recording_trackhost(edge_connection_t *conn, origin_circuit_t *circ) circ->build_state->chosen_exit->identity_digest, DIGEST_LEN); /* Add this exit/hostname pair to the addressmap. */ - len = strlen(conn->socks_request->address) + 1 /* '.' */ + - strlen(fp) + 1 /* '.' */ + - strlen("exit") + 1 /* '\0' */; - new_address = tor_malloc(len); - - tor_snprintf(new_address, len, "%s.%s.exit", + tor_asprintf(&new_address, "%s.%s.exit", conn->socks_request->address, fp); addressmap_register(conn->socks_request->address, new_address, diff --git a/src/or/circuituse.h b/src/or/circuituse.h index 1fdb19187..ab7f6a2fe 100644 --- a/src/or/circuituse.h +++ b/src/or/circuituse.h @@ -50,5 +50,8 @@ int connection_ap_handshake_attach_chosen_circuit(edge_connection_t *conn, crypt_path_t *cpath); int connection_ap_handshake_attach_circuit(edge_connection_t *conn); +int hostname_in_track_host_exits(const or_options_t *options, + const char *address); + #endif diff --git a/src/or/command.c b/src/or/command.c index 4b70deeef..d24373eec 100644 --- a/src/or/command.c +++ b/src/or/command.c @@ -276,8 +276,8 @@ command_process_create_cell(cell_t *cell, or_connection_t *conn) if (node) { char *p = esc_for_log(node_get_platform(node)); log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, - "Details: nickname \"%s\", platform %s.", - node_get_nickname(node), p); + "Details: router %s, platform %s.", + node_describe(node), p); tor_free(p); } return; @@ -649,6 +649,7 @@ command_process_netinfo_cell(cell_t *cell, or_connection_t *conn) /* XXX maybe act on my_apparent_addr, if the source is sufficiently * trustworthy. */ + (void)my_apparent_addr; if (connection_or_set_state_open(conn)<0) connection_mark_for_close(TO_CONN(conn)); diff --git a/src/or/config.c b/src/or/config.c index d17ed2462..4aabe6b95 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -38,11 +38,15 @@ #include <shlobj.h> #endif +#include "procmon.h" + /** Enumeration of types which option values can take */ typedef enum config_type_t { CONFIG_TYPE_STRING = 0, /**< An arbitrary string. */ CONFIG_TYPE_FILENAME, /**< A filename: some prefixes get expanded. */ CONFIG_TYPE_UINT, /**< A non-negative integer less than MAX_INT */ + CONFIG_TYPE_PORT, /**< A port from 1...65535, 0 for "not set", or + * "auto". */ CONFIG_TYPE_INTERVAL, /**< A number of seconds, with optional units*/ CONFIG_TYPE_MSEC_INTERVAL,/**< A number of milliseconds, with optional * units */ @@ -208,8 +212,11 @@ static config_var_t _option_vars[] = { V(ConstrainedSockSize, MEMUNIT, "8192"), V(ContactInfo, STRING, NULL), V(ControlListenAddress, LINELIST, NULL), - V(ControlPort, UINT, "0"), + V(ControlPort, PORT, "0"), + V(ControlPortFileGroupReadable,BOOL, "0"), + V(ControlPortWriteToFile, FILENAME, NULL), V(ControlSocket, LINELIST, NULL), + V(ControlSocketsGroupWritable, BOOL, "0"), V(CookieAuthentication, BOOL, "0"), V(CookieAuthFileGroupReadable, BOOL, "0"), V(CookieAuthFile, STRING, NULL), @@ -221,7 +228,7 @@ static config_var_t _option_vars[] = { V(DirListenAddress, LINELIST, NULL), OBSOLETE("DirFetchPeriod"), V(DirPolicy, LINELIST, NULL), - V(DirPort, UINT, "0"), + V(DirPort, PORT, "0"), V(DirPortFrontPage, FILENAME, NULL), OBSOLETE("DirPostPeriod"), OBSOLETE("DirRecordUsageByCountry"), @@ -232,7 +239,7 @@ static config_var_t _option_vars[] = { VAR("DirServer", LINELIST, DirServers, NULL), V(DisableAllSwap, BOOL, "0"), V(DisableIOCP, BOOL, "1"), - V(DNSPort, UINT, "0"), + V(DNSPort, PORT, "0"), V(DNSListenAddress, LINELIST, NULL), V(DownloadExtraInfo, BOOL, "0"), V(EnforceDistinctSubnets, BOOL, "1"), @@ -303,7 +310,7 @@ static config_var_t _option_vars[] = { OBSOLETE("LogFile"), V(LogTimeGranularity, MSEC_INTERVAL, "1 second"), V(LongLivedPorts, CSV, - "21,22,706,1863,5050,5190,5222,5223,6667,6697,8300"), + "21,22,706,1863,5050,5190,5222,5223,6523,6667,6697,8300"), VAR("MapAddress", LINELIST, AddressMap, NULL), V(MaxAdvertisedBandwidth, MEMUNIT, "1 GB"), V(MaxCircuitDirtiness, INTERVAL, "10 minutes"), @@ -313,7 +320,7 @@ static config_var_t _option_vars[] = { V(NewCircuitPeriod, INTERVAL, "30 seconds"), VAR("NamingAuthoritativeDirectory",BOOL, NamingAuthoritativeDir, "0"), V(NATDListenAddress, LINELIST, NULL), - V(NATDPort, UINT, "0"), + V(NATDPort, PORT, "0"), V(Nickname, STRING, NULL), V(WarnUnsafeSocks, BOOL, "1"), OBSOLETE("NoPublish"), @@ -321,7 +328,7 @@ static config_var_t _option_vars[] = { V(NumCPUs, UINT, "0"), V(NumEntryGuards, UINT, "3"), V(ORListenAddress, LINELIST, NULL), - V(ORPort, UINT, "0"), + V(ORPort, PORT, "0"), V(OutboundBindAddress, STRING, NULL), OBSOLETE("PathlenCoinWeight"), V(PerConnBWBurst, MEMUNIT, "0"), @@ -366,7 +373,7 @@ static config_var_t _option_vars[] = { V(ShutdownWaitLength, INTERVAL, "30 seconds"), V(SocksListenAddress, LINELIST, NULL), V(SocksPolicy, LINELIST, NULL), - V(SocksPort, UINT, "9050"), + V(SocksPort, PORT, "9050"), V(SocksTimeout, INTERVAL, "2 minutes"), OBSOLETE("StatusFetchPeriod"), V(StrictNodes, BOOL, "0"), @@ -377,7 +384,7 @@ static config_var_t _option_vars[] = { V(TrackHostExitsExpire, INTERVAL, "30 minutes"), OBSOLETE("TrafficShaping"), V(TransListenAddress, LINELIST, NULL), - V(TransPort, UINT, "0"), + V(TransPort, PORT, "0"), V(TunnelDirConns, BOOL, "1"), V(UpdateBridgesFromAuthority, BOOL, "0"), V(UseBridges, BOOL, "0"), @@ -406,6 +413,7 @@ static config_var_t _option_vars[] = { VAR("__LeaveStreamsUnattached",BOOL, LeaveStreamsUnattached, "0"), VAR("__HashedControlSessionPassword", LINELIST, HashedControlSessionPassword, NULL), + VAR("__OwningControllerProcess",STRING,OwningControllerProcess, NULL), V(MinUptimeHidServDirectoryV2, INTERVAL, "24 hours"), V(_UsingTestNetworkDefaults, BOOL, "0"), @@ -414,7 +422,7 @@ static config_var_t _option_vars[] = { /** Override default values with these if the user sets the TestingTorNetwork * option. */ -static config_var_t testing_tor_network_defaults[] = { +static const config_var_t testing_tor_network_defaults[] = { V(ServerDNSAllowBrokenConfig, BOOL, "1"), V(DirAllowPrivateAddresses, BOOL, "1"), V(EnforceDistinctSubnets, BOOL, "0"), @@ -538,45 +546,49 @@ static char *get_windows_conf_root(void); #endif static void config_line_append(config_line_t **lst, const char *key, const char *val); -static void option_clear(config_format_t *fmt, or_options_t *options, - config_var_t *var); -static void option_reset(config_format_t *fmt, or_options_t *options, - config_var_t *var, int use_defaults); -static void config_free(config_format_t *fmt, void *options); +static void option_clear(const config_format_t *fmt, or_options_t *options, + const config_var_t *var); +static void option_reset(const config_format_t *fmt, or_options_t *options, + const config_var_t *var, int use_defaults); +static void config_free(const config_format_t *fmt, void *options); static int config_lines_eq(config_line_t *a, config_line_t *b); -static int option_is_same(config_format_t *fmt, - or_options_t *o1, or_options_t *o2, +static int option_is_same(const config_format_t *fmt, + const or_options_t *o1, const or_options_t *o2, const char *name); -static or_options_t *options_dup(config_format_t *fmt, or_options_t *old); -static int options_validate(or_options_t *old_options, or_options_t *options, +static or_options_t *options_dup(const config_format_t *fmt, + const or_options_t *old); +static int options_validate(or_options_t *old_options, + or_options_t *options, int from_setconf, char **msg); -static int options_act_reversible(or_options_t *old_options, char **msg); -static int options_act(or_options_t *old_options); -static int options_transition_allowed(or_options_t *old, or_options_t *new, +static int options_act_reversible(const or_options_t *old_options, char **msg); +static int options_act(const or_options_t *old_options); +static int options_transition_allowed(const or_options_t *old, + const or_options_t *new, char **msg); -static int options_transition_affects_workers(or_options_t *old_options, - or_options_t *new_options); -static int options_transition_affects_descriptor(or_options_t *old_options, - or_options_t *new_options); +static int options_transition_affects_workers( + const or_options_t *old_options, const or_options_t *new_options); +static int options_transition_affects_descriptor( + const or_options_t *old_options, const or_options_t *new_options); static int check_nickname_list(const char *lst, const char *name, char **msg); -static void config_register_addressmaps(or_options_t *options); +static void config_register_addressmaps(const or_options_t *options); static int parse_bridge_line(const char *line, int validate_only); static int parse_dir_server_line(const char *line, dirinfo_type_t required_type, int validate_only); static int validate_data_directory(or_options_t *options); -static int write_configuration_file(const char *fname, or_options_t *options); -static config_line_t *get_assigned_option(config_format_t *fmt, - void *options, const char *key, - int escape_val); -static void config_init(config_format_t *fmt, void *options); +static int write_configuration_file(const char *fname, + const or_options_t *options); +static config_line_t *get_assigned_option(const config_format_t *fmt, + const void *options, const char *key, + int escape_val); +static void config_init(const config_format_t *fmt, void *options); static int or_state_validate(or_state_t *old_options, or_state_t *options, int from_setconf, char **msg); static int or_state_load(void); static int options_init_logs(or_options_t *options, int validate_only); -static int is_listening_on_low_port(uint16_t port_option, +static int is_listening_on_low_port(int port_option, const config_line_t *listen_options); static uint64_t config_parse_memunit(const char *s, int *ok); @@ -609,7 +621,7 @@ static config_var_t state_extra_var = { }; /** Configuration format for or_state_t. */ -static config_format_t state_format = { +static const config_format_t state_format = { sizeof(or_state_t), OR_STATE_MAGIC, STRUCT_OFFSET(or_state_t, _magic), @@ -643,7 +655,7 @@ get_dirportfrontpage(void) /** Allocate an empty configuration object of a given format type. */ static void * -config_alloc(config_format_t *fmt) +config_alloc(const config_format_t *fmt) { void *opts = tor_malloc_zero(fmt->size); *(uint32_t*)STRUCT_VAR_P(opts, fmt->magic_offset) = fmt->magic; @@ -653,12 +665,19 @@ config_alloc(config_format_t *fmt) /** Return the currently configured options. */ or_options_t * -get_options(void) +get_options_mutable(void) { tor_assert(global_options); return global_options; } +/** Returns the currently configured options */ +const or_options_t * +get_options(void) +{ + return get_options_mutable(); +} + /** Change the current global options to contain <b>new_val</b> instead of * their current value; take action based on the new value; free the old value * as necessary. Returns 0 on success, -1 on failure. @@ -895,8 +914,8 @@ validate_dir_authorities(or_options_t *options, or_options_t *old_options) * as appropriate. */ static int -consider_adding_dir_authorities(or_options_t *options, - or_options_t *old_options) +consider_adding_dir_authorities(const or_options_t *options, + const or_options_t *old_options) { config_line_t *cl; int need_to_update = @@ -950,12 +969,12 @@ consider_adding_dir_authorities(or_options_t *options, * Return 0 if all goes well, return -1 if things went badly. */ static int -options_act_reversible(or_options_t *old_options, char **msg) +options_act_reversible(const or_options_t *old_options, char **msg) { smartlist_t *new_listeners = smartlist_create(); smartlist_t *replaced_listeners = smartlist_create(); static int libevent_initialized = 0; - or_options_t *options = get_options(); + or_options_t *options = get_options_mutable(); int running_tor = options->command == CMD_RUN_TOR; int set_conn_limit = 0; int r = -1; @@ -970,9 +989,15 @@ options_act_reversible(or_options_t *old_options, char **msg) } #ifndef HAVE_SYS_UN_H - if (options->ControlSocket) { - *msg = tor_strdup("Unix domain sockets (ControlSocket) not supported" - " on this OS/with this build."); + if (options->ControlSocket || options->ControlSocketsGroupWritable) { + *msg = tor_strdup("Unix domain sockets (ControlSocket) not supported " + "on this OS/with this build."); + goto rollback; + } +#else + if (options->ControlSocketsGroupWritable && !options->ControlSocket) { + *msg = tor_strdup("Setting ControlSocketGroupWritable without setting" + "a ControlSocket makes no sense."); goto rollback; } #endif @@ -1033,7 +1058,8 @@ options_act_reversible(or_options_t *old_options, char **msg) /* Ensure data directory is private; create if possible. */ if (check_private_dir(options->DataDirectory, - running_tor ? CPD_CREATE : CPD_CHECK)<0) { + running_tor ? CPD_CREATE : CPD_CHECK, + options->User)<0) { tor_asprintf(msg, "Couldn't access/create private data directory \"%s\"", options->DataDirectory); @@ -1041,12 +1067,13 @@ options_act_reversible(or_options_t *old_options, char **msg) /* No need to roll back, since you can't change the value. */ } - if (directory_caches_v2_dir_info(options)) { + if (directory_caches_v2_dir_info(options)) { size_t len = strlen(options->DataDirectory)+32; char *fn = tor_malloc(len); tor_snprintf(fn, len, "%s"PATH_SEPARATOR"cached-status", options->DataDirectory); - if (check_private_dir(fn, running_tor ? CPD_CREATE : CPD_CHECK) < 0) { + if (check_private_dir(fn, running_tor ? CPD_CREATE : CPD_CHECK, + options->User) < 0) { tor_asprintf(msg, "Couldn't access/create private data directory \"%s\"", fn); tor_free(fn); @@ -1116,7 +1143,7 @@ options_act_reversible(or_options_t *old_options, char **msg) /** If we need to have a GEOIP ip-to-country map to run with our configured * options, return 1 and set *<b>reason_out</b> to a description of why. */ int -options_need_geoip_info(or_options_t *options, const char **reason_out) +options_need_geoip_info(const or_options_t *options, const char **reason_out) { int bridge_usage = options->BridgeRelay && options->BridgeRecordUsageByCountry; @@ -1141,7 +1168,7 @@ options_need_geoip_info(or_options_t *options, const char **reason_out) /** Return the bandwidthrate that we are going to report to the authorities * based on the config options. */ uint32_t -get_effective_bwrate(or_options_t *options) +get_effective_bwrate(const or_options_t *options) { uint64_t bw = options->BandwidthRate; if (bw > options->MaxAdvertisedBandwidth) @@ -1155,7 +1182,7 @@ get_effective_bwrate(or_options_t *options) /** Return the bandwidthburst that we are going to report to the authorities * based on the config options. */ uint32_t -get_effective_bwburst(or_options_t *options) +get_effective_bwburst(const or_options_t *options) { uint64_t bw = options->BandwidthBurst; if (options->RelayBandwidthBurst > 0 && bw > options->RelayBandwidthBurst) @@ -1174,12 +1201,14 @@ get_effective_bwburst(or_options_t *options) * here yet. Some is still in do_hup() and other places. */ static int -options_act(or_options_t *old_options) +options_act(const or_options_t *old_options) { config_line_t *cl; - or_options_t *options = get_options(); + or_options_t *options = get_options_mutable(); int running_tor = options->command == CMD_RUN_TOR; char *msg; + const int transition_affects_workers = + old_options && options_transition_affects_workers(old_options, options); if (running_tor && !have_lockfile()) { if (try_locking(options, 1) < 0) @@ -1190,7 +1219,7 @@ options_act(or_options_t *old_options) return -1; if (options->Bridges) { - clear_bridge_list(); + mark_bridge_list(); for (cl = options->Bridges; cl; cl = cl->next) { if (parse_bridge_line(cl->value, 0)<0) { log_warn(LD_BUG, @@ -1198,6 +1227,7 @@ options_act(or_options_t *old_options) return -1; } } + sweep_bridge_list(); } if (running_tor && rend_config_services(options, 0)<0) { @@ -1230,6 +1260,17 @@ options_act(or_options_t *old_options) finish_daemon(options->DataDirectory); } + /* We want to reinit keys as needed before we do much of anything else: + keys are important, and other things can depend on them. */ + if (transition_affects_workers || + (options->V3AuthoritativeDir && (!old_options || + !old_options->V3AuthoritativeDir))) { + if (init_keys() < 0) { + log_warn(LD_BUG,"Error initializing keys; exiting"); + return -1; + } + } + /* Write our PID to the PID file. If we do not have write permissions we * will log a warning */ if (options->PidFile) @@ -1251,6 +1292,8 @@ options_act(or_options_t *old_options) return -1; } + monitor_owning_controller_process(options->OwningControllerProcess); + /* reload keys as needed for rendezvous services. */ if (rend_service_load_keys()<0) { log_warn(LD_GENERAL,"Error loading rendezvous service keys"); @@ -1281,7 +1324,12 @@ options_act(or_options_t *old_options) /* Check for transitions that need action. */ if (old_options) { + int revise_trackexithosts = 0; + int revise_automap_entries = 0; if ((options->UseEntryGuards && !old_options->UseEntryGuards) || + options->UseBridges != old_options->UseBridges || + (options->UseBridges && + !config_lines_eq(options->Bridges, old_options->Bridges)) || !routerset_equal(old_options->ExcludeNodes,options->ExcludeNodes) || !routerset_equal(old_options->ExcludeExitNodes, options->ExcludeExitNodes) || @@ -1289,13 +1337,36 @@ options_act(or_options_t *old_options) !routerset_equal(old_options->ExitNodes, options->ExitNodes) || options->StrictNodes != old_options->StrictNodes) { log_info(LD_CIRC, - "Changed to using entry guards, or changed preferred or " - "excluded node lists. Abandoning previous circuits."); + "Changed to using entry guards or bridges, or changed " + "preferred or excluded node lists. " + "Abandoning previous circuits."); circuit_mark_all_unused_circs(); circuit_expire_all_dirty_circs(); + revise_trackexithosts = 1; + } + + if (!smartlist_strings_eq(old_options->TrackHostExits, + options->TrackHostExits)) + revise_trackexithosts = 1; + + if (revise_trackexithosts) addressmap_clear_excluded_trackexithosts(options); + + if (!options->AutomapHostsOnResolve) { + if (old_options->AutomapHostsOnResolve) + revise_automap_entries = 1; + } else { + if (!smartlist_strings_eq(old_options->AutomapHostsSuffixes, + options->AutomapHostsSuffixes)) + revise_automap_entries = 1; + else if (!opt_streq(old_options->VirtualAddrNetwork, + options->VirtualAddrNetwork)) + revise_automap_entries = 1; } + if (revise_automap_entries) + addressmap_clear_invalid_automaps(options); + /* How long should we delay counting bridge stats after becoming a bridge? * We use this so we don't count people who used our bridge thinking it is * a relay. If you change this, don't forget to change the log message @@ -1322,14 +1393,10 @@ options_act(or_options_t *old_options) } } - if (options_transition_affects_workers(old_options, options)) { + if (transition_affects_workers) { log_info(LD_GENERAL, "Worker-related options changed. Rotating workers."); - if (init_keys() < 0) { - log_warn(LD_BUG,"Error initializing keys; exiting"); - return -1; - } if (server_mode(options) && !server_mode(old_options)) { ip_address_changed(0); if (can_complete_circuit || !any_predicted_circuits(time(NULL))) @@ -1343,9 +1410,6 @@ options_act(or_options_t *old_options) return -1; } - if (options->V3AuthoritativeDir && !old_options->V3AuthoritativeDir) - init_keys(); - if (options->PerConnBWRate != old_options->PerConnBWRate || options->PerConnBWBurst != old_options->PerConnBWBurst) connection_or_update_token_buckets(get_connection_array(), options); @@ -1453,7 +1517,7 @@ options_act(or_options_t *old_options) */ if (!old_options || options_transition_affects_descriptor(old_options, options)) - mark_my_descriptor_dirty(); + mark_my_descriptor_dirty("config change"); /* We may need to reschedule some directory stuff if our status changed. */ if (old_options) { @@ -1497,7 +1561,7 @@ options_act(or_options_t *old_options) * apply abbreviations that work for the config file and the command line. * If <b>warn_obsolete</b> is set, warn about deprecated names. */ static const char * -expand_abbrev(config_format_t *fmt, const char *option, int command_line, +expand_abbrev(const config_format_t *fmt, const char *option, int command_line, int warn_obsolete) { int i; @@ -1657,12 +1721,9 @@ config_free_lines(config_line_t *front) } } -/** If <b>key</b> is a configuration option, return the corresponding - * config_var_t. Otherwise, if <b>key</b> is a non-standard abbreviation, - * warn, and return the corresponding config_var_t. Otherwise return NULL. - */ +/** As config_find_option, but return a non-const pointer. */ static config_var_t * -config_find_option(config_format_t *fmt, const char *key) +config_find_option_mutable(config_format_t *fmt, const char *key) { int i; size_t keylen = strlen(key); @@ -1687,9 +1748,20 @@ config_find_option(config_format_t *fmt, const char *key) return NULL; } +/** If <b>key</b> is a configuration option, return the corresponding const + * config_var_t. Otherwise, if <b>key</b> is a non-standard abbreviation, + * warn, and return the corresponding const config_var_t. Otherwise return + * NULL. + */ +static const config_var_t * +config_find_option(const config_format_t *fmt, const char *key) +{ + return config_find_option_mutable((config_format_t*)fmt, key); +} + /** Return the number of option entries in <b>fmt</b>. */ static int -config_count_options(config_format_t *fmt) +config_count_options(const config_format_t *fmt) { int i; for (i=0; fmt->vars[i].name; ++i) @@ -1707,11 +1779,11 @@ config_count_options(config_format_t *fmt) * Called from config_assign_line() and option_reset(). */ static int -config_assign_value(config_format_t *fmt, or_options_t *options, +config_assign_value(const config_format_t *fmt, or_options_t *options, config_line_t *c, char **msg) { int i, ok; - config_var_t *var; + const config_var_t *var; void *lvalue; CHECK(fmt, options); @@ -1723,8 +1795,16 @@ config_assign_value(config_format_t *fmt, or_options_t *options, switch (var->type) { + case CONFIG_TYPE_PORT: + if (!strcasecmp(c->value, "auto")) { + *(int *)lvalue = CFG_AUTO_PORT; + break; + } + /* fall through */ case CONFIG_TYPE_UINT: - i = (int)tor_parse_long(c->value, 10, 0, INT_MAX, &ok, NULL); + i = (int)tor_parse_long(c->value, 10, 0, + var->type==CONFIG_TYPE_PORT ? 65535 : INT_MAX, + &ok, NULL); if (!ok) { tor_asprintf(msg, "Int keyword '%s %s' is malformed or out of bounds.", @@ -1865,11 +1945,11 @@ config_assign_value(config_format_t *fmt, or_options_t *options, * Called from config_assign(). */ static int -config_assign_line(config_format_t *fmt, or_options_t *options, +config_assign_line(const config_format_t *fmt, or_options_t *options, config_line_t *c, int use_defaults, int clear_first, bitarray_t *options_seen, char **msg) { - config_var_t *var; + const config_var_t *var; CHECK(fmt, options); @@ -1930,10 +2010,10 @@ config_assign_line(config_format_t *fmt, or_options_t *options, /** Restore the option named <b>key</b> in options to its default value. * Called from config_assign(). */ static void -config_reset_line(config_format_t *fmt, or_options_t *options, +config_reset_line(const config_format_t *fmt, or_options_t *options, const char *key, int use_defaults) { - config_var_t *var; + const config_var_t *var; CHECK(fmt, options); @@ -1948,7 +2028,7 @@ config_reset_line(config_format_t *fmt, or_options_t *options, int option_is_recognized(const char *key) { - config_var_t *var = config_find_option(&options_format, key); + const config_var_t *var = config_find_option(&options_format, key); return (var != NULL); } @@ -1957,14 +2037,14 @@ option_is_recognized(const char *key) const char * option_get_canonical_name(const char *key) { - config_var_t *var = config_find_option(&options_format, key); + const config_var_t *var = config_find_option(&options_format, key); return var ? var->name : NULL; } /** Return a canonical list of the options assigned for key. */ config_line_t * -option_get_assignment(or_options_t *options, const char *key) +option_get_assignment(const or_options_t *options, const char *key) { return get_assigned_option(&options_format, options, key, 1); } @@ -2017,10 +2097,10 @@ config_lines_dup(const config_line_t *inp) * value needs to be quoted before it's put in a config file, quote and * escape that value. Return NULL if no such key exists. */ static config_line_t * -get_assigned_option(config_format_t *fmt, void *options, +get_assigned_option(const config_format_t *fmt, const void *options, const char *key, int escape_val) { - config_var_t *var; + const config_var_t *var; const void *value; config_line_t *result; tor_assert(options && key); @@ -2058,6 +2138,13 @@ get_assigned_option(config_format_t *fmt, void *options, } escape_val = 0; /* Can't need escape. */ break; + case CONFIG_TYPE_PORT: + if (*(int*)value == CFG_AUTO_PORT) { + result->value = tor_strdup("auto"); + escape_val = 0; + break; + } + /* fall through */ case CONFIG_TYPE_INTERVAL: case CONFIG_TYPE_MSEC_INTERVAL: case CONFIG_TYPE_UINT: @@ -2195,7 +2282,7 @@ options_trial_assign() calls config_assign(1, 1) returns. */ static int -config_assign(config_format_t *fmt, void *options, config_line_t *list, +config_assign(const config_format_t *fmt, void *options, config_line_t *list, int use_defaults, int clear_first, char **msg) { config_line_t *p; @@ -2257,7 +2344,7 @@ options_trial_assign(config_line_t *list, int use_defaults, return r; } - if (options_validate(get_options(), trial_options, 1, msg) < 0) { + if (options_validate(get_options_mutable(), trial_options, 1, msg) < 0) { config_free(&options_format, trial_options); return SETOPT_ERR_PARSE; /*XXX make this a separate return value. */ } @@ -2279,7 +2366,8 @@ options_trial_assign(config_line_t *list, int use_defaults, /** Reset config option <b>var</b> to 0, 0.0, NULL, or the equivalent. * Called from option_reset() and config_free(). */ static void -option_clear(config_format_t *fmt, or_options_t *options, config_var_t *var) +option_clear(const config_format_t *fmt, or_options_t *options, + const config_var_t *var) { void *lvalue = STRUCT_VAR_P(options, var->var_offset); (void)fmt; /* unused */ @@ -2297,6 +2385,7 @@ option_clear(config_format_t *fmt, or_options_t *options, config_var_t *var) case CONFIG_TYPE_INTERVAL: case CONFIG_TYPE_MSEC_INTERVAL: case CONFIG_TYPE_UINT: + case CONFIG_TYPE_PORT: case CONFIG_TYPE_BOOL: *(int*)lvalue = 0; break; @@ -2336,8 +2425,8 @@ option_clear(config_format_t *fmt, or_options_t *options, config_var_t *var) * <b>use_defaults</b>, set it to its default value. * Called by config_init() and option_reset_line() and option_assign_line(). */ static void -option_reset(config_format_t *fmt, or_options_t *options, - config_var_t *var, int use_defaults) +option_reset(const config_format_t *fmt, or_options_t *options, + const config_var_t *var, int use_defaults) { config_line_t *c; char *msg = NULL; @@ -2377,7 +2466,7 @@ list_torrc_options(void) int i; smartlist_t *lines = smartlist_create(); for (i = 0; _option_vars[i].name; ++i) { - config_var_t *var = &_option_vars[i]; + const config_var_t *var = &_option_vars[i]; if (var->type == CONFIG_TYPE_OBSOLETE || var->type == CONFIG_TYPE_LINELIST_V) continue; @@ -2396,7 +2485,7 @@ static uint32_t last_resolved_addr = 0; * public IP address. */ int -resolve_my_address(int warn_severity, or_options_t *options, +resolve_my_address(int warn_severity, const or_options_t *options, uint32_t *addr_out, char **hostname_out) { struct in_addr in; @@ -2572,7 +2661,7 @@ is_local_addr(const tor_addr_t *addr) /** Release storage held by <b>options</b>. */ static void -config_free(config_format_t *fmt, void *options) +config_free(const config_format_t *fmt, void *options) { int i; @@ -2611,8 +2700,9 @@ config_lines_eq(config_line_t *a, config_line_t *b) * and <b>o2</b>. Must not be called for LINELIST_S or OBSOLETE options. */ static int -option_is_same(config_format_t *fmt, - or_options_t *o1, or_options_t *o2, const char *name) +option_is_same(const config_format_t *fmt, + const or_options_t *o1, const or_options_t *o2, + const char *name) { config_line_t *c1, *c2; int r = 1; @@ -2629,7 +2719,7 @@ option_is_same(config_format_t *fmt, /** Copy storage held by <b>old</b> into a new or_options_t and return it. */ static or_options_t * -options_dup(config_format_t *fmt, or_options_t *old) +options_dup(const config_format_t *fmt, const or_options_t *old) { or_options_t *newopts; int i; @@ -2677,7 +2767,7 @@ options_init(or_options_t *options) * it is, or 0 if it isn't or the concept of a low port isn't applicable for * the platform we're on. */ static int -is_listening_on_low_port(uint16_t port_option, +is_listening_on_low_port(int port_option, const config_line_t *listen_options) { #ifdef MS_WINDOWS @@ -2705,10 +2795,10 @@ is_listening_on_low_port(uint16_t port_option, /** Set all vars in the configuration object <b>options</b> to their default * values. */ static void -config_init(config_format_t *fmt, void *options) +config_init(const config_format_t *fmt, void *options) { int i; - config_var_t *var; + const config_var_t *var; CHECK(fmt, options); for (i=0; fmt->vars[i].name; ++i) { @@ -2724,7 +2814,7 @@ config_init(config_format_t *fmt, void *options) * Else, if comment_defaults, write default values as comments. */ static char * -config_dump(config_format_t *fmt, void *options, int minimal, +config_dump(const config_format_t *fmt, const void *options, int minimal, int comment_defaults) { smartlist_t *elements; @@ -2792,7 +2882,7 @@ config_dump(config_format_t *fmt, void *options, int minimal, * include options that are the same as Tor's defaults. */ char * -options_dump(or_options_t *options, int minimal) +options_dump(const or_options_t *options, int minimal) { return config_dump(&options_format, options, minimal, 0); } @@ -2926,9 +3016,6 @@ options_validate(or_options_t *old_options, or_options_t *options, tor_assert(msg); *msg = NULL; - if (options->ORPort < 0 || options->ORPort > 65535) - REJECT("ORPort option out of bounds."); - if (server_mode(options) && (!strcmpstart(uname, "Windows 95") || !strcmpstart(uname, "Windows 98") || @@ -3037,18 +3124,6 @@ options_validate(or_options_t *old_options, or_options_t *options, REJECT("Can't use a relative path to torrc when RunAsDaemon is set."); #endif - if (options->SocksPort < 0 || options->SocksPort > 65535) - REJECT("SocksPort option out of bounds."); - - if (options->DNSPort < 0 || options->DNSPort > 65535) - REJECT("DNSPort option out of bounds."); - - if (options->TransPort < 0 || options->TransPort > 65535) - REJECT("TransPort option out of bounds."); - - if (options->NATDPort < 0 || options->NATDPort > 65535) - REJECT("NATDPort option out of bounds."); - if (options->SocksPort == 0 && options->TransPort == 0 && options->NATDPort == 0 && options->ORPort == 0 && options->DNSPort == 0 && !options->RendConfigLines) @@ -3057,12 +3132,6 @@ options_validate(or_options_t *old_options, or_options_t *options, "undefined, and there aren't any hidden services configured. " "Tor will still run, but probably won't do anything."); - if (options->ControlPort < 0 || options->ControlPort > 65535) - REJECT("ControlPort option out of bounds."); - - if (options->DirPort < 0 || options->DirPort > 65535) - REJECT("DirPort option out of bounds."); - #ifndef USE_TRANSPARENT if (options->TransPort || options->TransListenAddress) REJECT("TransPort and TransListenAddress are disabled in this build."); @@ -3451,8 +3520,8 @@ options_validate(or_options_t *old_options, or_options_t *options, } if (options->HTTPProxyAuthenticator) { - if (strlen(options->HTTPProxyAuthenticator) >= 48) - REJECT("HTTPProxyAuthenticator is too long (>= 48 chars)."); + if (strlen(options->HTTPProxyAuthenticator) >= 512) + REJECT("HTTPProxyAuthenticator is too long (>= 512 chars)."); } if (options->HTTPSProxy) { /* parse it now */ @@ -3465,8 +3534,8 @@ options_validate(or_options_t *old_options, or_options_t *options, } if (options->HTTPSProxyAuthenticator) { - if (strlen(options->HTTPSProxyAuthenticator) >= 48) - REJECT("HTTPSProxyAuthenticator is too long (>= 48 chars)."); + if (strlen(options->HTTPSProxyAuthenticator) >= 512) + REJECT("HTTPSProxyAuthenticator is too long (>= 512 chars)."); } if (options->Socks4Proxy) { /* parse it now */ @@ -3529,6 +3598,16 @@ options_validate(or_options_t *old_options, or_options_t *options, } } + if (options->OwningControllerProcess) { + const char *validate_pspec_msg = NULL; + if (tor_validate_process_specifier(options->OwningControllerProcess, + &validate_pspec_msg)) { + tor_asprintf(msg, "Bad OwningControllerProcess: %s", + validate_pspec_msg); + return -1; + } + } + if (options->ControlListenAddress) { int all_are_local = 1; config_line_t *ln; @@ -3798,7 +3877,8 @@ opt_streq(const char *s1, const char *s2) /** Check if any of the previous options have changed but aren't allowed to. */ static int -options_transition_allowed(or_options_t *old, or_options_t *new_val, +options_transition_allowed(const or_options_t *old, + const or_options_t *new_val, char **msg) { if (!old) @@ -3854,15 +3934,15 @@ options_transition_allowed(or_options_t *old, or_options_t *new_val, /** Return 1 if any change from <b>old_options</b> to <b>new_options</b> * will require us to rotate the CPU and DNS workers; else return 0. */ static int -options_transition_affects_workers(or_options_t *old_options, - or_options_t *new_options) +options_transition_affects_workers(const or_options_t *old_options, + const or_options_t *new_options) { if (!opt_streq(old_options->DataDirectory, new_options->DataDirectory) || old_options->NumCPUs != new_options->NumCPUs || old_options->ORPort != new_options->ORPort || old_options->ServerDNSSearchDomains != new_options->ServerDNSSearchDomains || - old_options->SafeLogging != new_options->SafeLogging || + old_options->_SafeLogging != new_options->_SafeLogging || old_options->ClientOnly != new_options->ClientOnly || public_server_mode(old_options) != public_server_mode(new_options) || !config_lines_eq(old_options->Logs, new_options->Logs) || @@ -3878,8 +3958,8 @@ options_transition_affects_workers(or_options_t *old_options, /** Return 1 if any change from <b>old_options</b> to <b>new_options</b> * will require us to generate a new descriptor; else return 0. */ static int -options_transition_affects_descriptor(or_options_t *old_options, - or_options_t *new_options) +options_transition_affects_descriptor(const or_options_t *old_options, + const or_options_t *new_options) { /* XXX We can be smarter here. If your DirPort isn't being * published and you just turned it off, no need to republish. Etc. */ @@ -3900,7 +3980,8 @@ options_transition_affects_descriptor(or_options_t *old_options, !opt_streq(old_options->ContactInfo, new_options->ContactInfo) || !opt_streq(old_options->MyFamily, new_options->MyFamily) || !opt_streq(old_options->AccountingStart, new_options->AccountingStart) || - old_options->AccountingMax != new_options->AccountingMax) + old_options->AccountingMax != new_options->AccountingMax || + public_server_mode(old_options) != public_server_mode(new_options)) return 1; return 0; @@ -4245,9 +4326,9 @@ options_init_from_string(const char *cf, /* Change defaults. */ int i; for (i = 0; testing_tor_network_defaults[i].name; ++i) { - config_var_t *new_var = &testing_tor_network_defaults[i]; + const config_var_t *new_var = &testing_tor_network_defaults[i]; config_var_t *old_var = - config_find_option(&options_format, new_var->name); + config_find_option_mutable(&options_format, new_var->name); tor_assert(new_var); tor_assert(old_var); old_var->initvalue = new_var->initvalue; @@ -4324,7 +4405,7 @@ get_torrc_fname(void) * configuration <b>options</b> */ static void -config_register_addressmaps(or_options_t *options) +config_register_addressmaps(const or_options_t *options) { smartlist_t *elts; config_line_t *opt; @@ -4754,7 +4835,7 @@ validate_data_directory(or_options_t *options) * doesn't begin with GENERATED_FILE_PREFIX, rename it. Otherwise * replace it. Return 0 on success, -1 on failure. */ static int -write_configuration_file(const char *fname, or_options_t *options) +write_configuration_file(const char *fname, const or_options_t *options) { char *old_val=NULL, *new_val=NULL, *new_conf=NULL; int rename_old = 0, r; @@ -5091,7 +5172,7 @@ get_or_state(void) * Note: Consider using the get_datadir_fname* macros in or.h. */ char * -options_get_datadir_fname2_suffix(or_options_t *options, +options_get_datadir_fname2_suffix(const or_options_t *options, const char *sub1, const char *sub2, const char *suffix) { @@ -5408,13 +5489,14 @@ getinfo_helper_config(control_connection_t *conn, smartlist_t *sl = smartlist_create(); int i; for (i = 0; _option_vars[i].name; ++i) { - config_var_t *var = &_option_vars[i]; + const config_var_t *var = &_option_vars[i]; const char *type; char *line; switch (var->type) { case CONFIG_TYPE_STRING: type = "String"; break; case CONFIG_TYPE_FILENAME: type = "Filename"; break; case CONFIG_TYPE_UINT: type = "Integer"; break; + case CONFIG_TYPE_PORT: type = "Port"; break; case CONFIG_TYPE_INTERVAL: type = "TimeInterval"; break; case CONFIG_TYPE_MSEC_INTERVAL: type = "TimeMsecInterval"; break; case CONFIG_TYPE_MEMUNIT: type = "DataSize"; break; diff --git a/src/or/config.h b/src/or/config.h index 49f7e25be..bc7119143 100644 --- a/src/or/config.h +++ b/src/or/config.h @@ -13,7 +13,8 @@ #define _TOR_CONFIG_H const char *get_dirportfrontpage(void); -or_options_t *get_options(void); +const or_options_t *get_options(void); +or_options_t *get_options_mutable(void); int set_options(or_options_t *new_val, char **msg); void config_free_all(void); const char *safe_str_client(const char *address); @@ -26,21 +27,21 @@ int config_get_lines(const char *string, config_line_t **result); void config_free_lines(config_line_t *front); setopt_err_t options_trial_assign(config_line_t *list, int use_defaults, int clear_first, char **msg); -int resolve_my_address(int warn_severity, or_options_t *options, +int resolve_my_address(int warn_severity, const or_options_t *options, uint32_t *addr, char **hostname_out); int is_local_addr(const tor_addr_t *addr) ATTR_PURE; void options_init(or_options_t *options); -char *options_dump(or_options_t *options, int minimal); +char *options_dump(const or_options_t *options, int minimal); int options_init_from_torrc(int argc, char **argv); setopt_err_t options_init_from_string(const char *cf, int command, const char *command_arg, char **msg); int option_is_recognized(const char *key); const char *option_get_canonical_name(const char *key); -config_line_t *option_get_assignment(or_options_t *options, +config_line_t *option_get_assignment(const or_options_t *options, const char *key); int options_save_current(void); const char *get_torrc_fname(void); -char *options_get_datadir_fname2_suffix(or_options_t *options, +char *options_get_datadir_fname2_suffix(const or_options_t *options, const char *sub1, const char *sub2, const char *suffix); #define get_datadir_fname2_suffix(sub1, sub2, suffix) \ @@ -63,14 +64,15 @@ or_state_t *get_or_state(void); int did_last_state_file_write_fail(void); int or_state_save(time_t now); -int options_need_geoip_info(or_options_t *options, const char **reason_out); +int options_need_geoip_info(const or_options_t *options, + const char **reason_out); int getinfo_helper_config(control_connection_t *conn, const char *question, char **answer, const char **errmsg); const char *tor_get_digests(void); -uint32_t get_effective_bwrate(or_options_t *options); -uint32_t get_effective_bwburst(or_options_t *options); +uint32_t get_effective_bwrate(const or_options_t *options); +uint32_t get_effective_bwburst(const or_options_t *options); #ifdef CONFIG_PRIVATE /* Used only by config.c and test.c */ diff --git a/src/or/connection.c b/src/or/connection.c index e7f2b0051..c84ee04d5 100644 --- a/src/or/connection.c +++ b/src/or/connection.c @@ -41,7 +41,7 @@ #endif static connection_t *connection_create_listener( - struct sockaddr *listensockaddr, + const struct sockaddr *listensockaddr, socklen_t listensocklen, int type, char* address); static void connection_init(time_t now, connection_t *conn, int type, @@ -60,8 +60,8 @@ static int connection_reached_eof(connection_t *conn); static int connection_read_to_buf(connection_t *conn, ssize_t *max_to_read, int *socket_error); static int connection_process_inbuf(connection_t *conn, int package_partial); -static void client_check_address_changed(int sock); -static void set_constrained_socket_buffers(int sock, int size); +static void client_check_address_changed(tor_socket_t sock); +static void set_constrained_socket_buffers(tor_socket_t sock, int size); static const char *connection_proxy_state_to_string(int state); static int connection_read_https_proxy_response(connection_t *conn); @@ -478,8 +478,8 @@ _connection_free(connection_t *conn) rend_data_free(dir_conn->rend_data); } - if (conn->s >= 0) { - log_debug(LD_NET,"closing fd %d.",conn->s); + if (SOCKET_OK(conn->s)) { + log_debug(LD_NET,"closing fd %d.",(int)conn->s); tor_close_socket(conn->s); conn->s = -1; } @@ -523,8 +523,7 @@ connection_free(connection_t *conn) } } if (conn->type == CONN_TYPE_CONTROL) { - TO_CONTROL_CONN(conn)->event_mask = 0; - control_update_global_event_mask(); + connection_control_closed(TO_CONTROL_CONN(conn)); } connection_unregister_events(conn); _connection_free(conn); @@ -620,7 +619,7 @@ connection_about_to_close_connection(connection_t *conn) circuit_n_conn_done(TO_OR_CONN(conn), 0); /* now mark things down as needed */ if (connection_or_nonopen_was_started_here(or_conn)) { - or_options_t *options = get_options(); + const or_options_t *options = get_options(); rep_hist_note_connect_failed(or_conn->identity_digest, now); entry_guard_register_connect_status(or_conn->identity_digest,0, !options->HTTPSProxy, now); @@ -707,14 +706,14 @@ connection_close_immediate(connection_t *conn) } if (conn->outbuf_flushlen) { log_info(LD_NET,"fd %d, type %s, state %s, %d bytes on outbuf.", - conn->s, conn_type_to_string(conn->type), + (int)conn->s, conn_type_to_string(conn->type), conn_state_to_string(conn->type, conn->state), (int)conn->outbuf_flushlen); } connection_unregister_events(conn); - if (conn->s >= 0) + if (SOCKET_OK(conn->s)) tor_close_socket(conn->s); conn->s = -1; if (conn->linked) @@ -783,7 +782,7 @@ connection_expire_held_open(void) log_fn(severity, LD_NET, "Giving up on marked_for_close conn that's been flushing " "for 15s (fd %d, type %s, state %s).", - conn->s, conn_type_to_string(conn->type), + (int)conn->s, conn_type_to_string(conn->type), conn_state_to_string(conn->type, conn->state)); conn->hold_open_until_flushed = 0; } @@ -802,7 +801,7 @@ connection_expire_held_open(void) * The listenaddr struct has to be freed by the caller. */ static struct sockaddr_in * -create_inet_sockaddr(const char *listenaddress, uint16_t listenport, +create_inet_sockaddr(const char *listenaddress, int listenport, char **readable_address, socklen_t *socklen_out) { struct sockaddr_in *listenaddr = NULL; uint32_t addr; @@ -814,8 +813,10 @@ create_inet_sockaddr(const char *listenaddress, uint16_t listenport, "Error parsing/resolving ListenAddress %s", listenaddress); goto err; } - if (usePort==0) - usePort = listenport; + if (usePort==0) { + if (listenport != CFG_AUTO_PORT) + usePort = listenport; + } listenaddr = tor_malloc_zero(sizeof(struct sockaddr_in)); listenaddr->sin_addr.s_addr = htonl(addr); @@ -853,7 +854,13 @@ create_unix_sockaddr(const char *listenaddress, char **readable_address, sockaddr = tor_malloc_zero(sizeof(struct sockaddr_un)); sockaddr->sun_family = AF_UNIX; - strncpy(sockaddr->sun_path, listenaddress, sizeof(sockaddr->sun_path)); + if (strlcpy(sockaddr->sun_path, listenaddress, sizeof(sockaddr->sun_path)) + >= sizeof(sockaddr->sun_path)) { + log_warn(LD_CONFIG, "Unix socket path '%s' is too long to fit.", + escaped(listenaddress)); + tor_free(sockaddr); + return NULL; + } if (readable_address) *readable_address = tor_strdup(listenaddress); @@ -894,6 +901,62 @@ warn_too_many_conns(void) } } +#ifdef HAVE_SYS_UN_H +/** Check whether we should be willing to open an AF_UNIX socket in + * <b>path</b>. Return 0 if we should go ahead and -1 if we shouldn't. */ +static int +check_location_for_unix_socket(const or_options_t *options, const char *path) +{ + int r = -1; + char *p = tor_strdup(path); + cpd_check_t flags = CPD_CHECK_MODE_ONLY; + if (get_parent_directory(p)<0) + goto done; + + if (options->ControlSocketsGroupWritable) + flags |= CPD_GROUP_OK; + + if (check_private_dir(p, flags, options->User) < 0) { + char *escpath, *escdir; + escpath = esc_for_log(path); + escdir = esc_for_log(p); + log_warn(LD_GENERAL, "Before Tor can create a control socket in %s, the " + "directory %s needs to exist, and to be accessible only by the " + "user%s account that is running Tor. (On some Unix systems, " + "anybody who can list a socket can conect to it, so Tor is " + "being careful.)", escpath, escdir, + options->ControlSocketsGroupWritable ? " and group" : ""); + tor_free(escpath); + tor_free(escdir); + goto done; + } + + r = 0; + done: + tor_free(p); + return r; +} +#endif + +/** Tell the TCP stack that it shouldn't wait for a long time after + * <b>sock</b> has closed before reusing its port. */ +static void +make_socket_reuseable(tor_socket_t sock) +{ +#ifdef MS_WINDOWS + (void) sock; +#else + int one=1; + + /* REUSEADDR on normal places means you can rebind to the port + * right after somebody else has let it go. But REUSEADDR on win32 + * means you can bind to the port _even when somebody else + * already has it bound_. So, don't do that on Win32. */ + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*) &one, + (socklen_t)sizeof(one)); +#endif +} + /** Bind a new non-blocking socket listening to the socket described * by <b>listensockaddr</b>. * @@ -901,12 +964,13 @@ warn_too_many_conns(void) * to the conn. */ static connection_t * -connection_create_listener(struct sockaddr *listensockaddr, socklen_t socklen, +connection_create_listener(const struct sockaddr *listensockaddr, + socklen_t socklen, int type, char* address) { connection_t *conn; - int s; /* the socket we're going to make */ - uint16_t usePort = 0; + tor_socket_t s; /* the socket we're going to make */ + uint16_t usePort = 0, gotPort = 0; int start_reading = 0; if (get_n_open_sockets() >= get_options()->_ConnLimit-1) { @@ -915,35 +979,25 @@ connection_create_listener(struct sockaddr *listensockaddr, socklen_t socklen, } if (listensockaddr->sa_family == AF_INET) { + tor_addr_t addr; int is_tcp = (type != CONN_TYPE_AP_DNS_LISTENER); -#ifndef MS_WINDOWS - int one=1; -#endif if (is_tcp) start_reading = 1; - usePort = ntohs( (uint16_t) - ((struct sockaddr_in *)listensockaddr)->sin_port); + tor_addr_from_sockaddr(&addr, listensockaddr, &usePort); log_notice(LD_NET, "Opening %s on %s:%d", - conn_type_to_string(type), address, usePort); + conn_type_to_string(type), fmt_addr(&addr), usePort); s = tor_open_socket(PF_INET, is_tcp ? SOCK_STREAM : SOCK_DGRAM, is_tcp ? IPPROTO_TCP: IPPROTO_UDP); - if (s < 0) { + if (!SOCKET_OK(s)) { log_warn(LD_NET,"Socket creation failed."); goto err; } -#ifndef MS_WINDOWS - /* REUSEADDR on normal places means you can rebind to the port - * right after somebody else has let it go. But REUSEADDR on win32 - * means you can bind to the port _even when somebody else - * already has it bound_. So, don't do that on Win32. */ - setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void*) &one, - (socklen_t)sizeof(one)); -#endif + make_socket_reuseable(s); if (bind(s,listensockaddr,socklen) < 0) { const char *helpfulhint = ""; @@ -964,6 +1018,21 @@ connection_create_listener(struct sockaddr *listensockaddr, socklen_t socklen, goto err; } } + + if (usePort != 0) { + gotPort = usePort; + } else { + tor_addr_t addr2; + struct sockaddr_storage ss; + socklen_t ss_len=sizeof(ss); + if (getsockname(s, (struct sockaddr*)&ss, &ss_len)<0) { + log_warn(LD_NET, "getsockname() couldn't learn address for %s: %s", + conn_type_to_string(type), + tor_socket_strerror(tor_socket_errno(s))); + gotPort = 0; + } + tor_addr_from_sockaddr(&addr2, (struct sockaddr*)&ss, &gotPort); + } #ifdef HAVE_SYS_UN_H } else if (listensockaddr->sa_family == AF_UNIX) { start_reading = 1; @@ -972,6 +1041,9 @@ connection_create_listener(struct sockaddr *listensockaddr, socklen_t socklen, * and listeners at the same time */ tor_assert(type == CONN_TYPE_CONTROL_LISTENER); + if (check_location_for_unix_socket(get_options(), address) < 0) + goto err; + log_notice(LD_NET, "Opening %s on %s", conn_type_to_string(type), address); @@ -991,6 +1063,15 @@ connection_create_listener(struct sockaddr *listensockaddr, socklen_t socklen, tor_socket_strerror(tor_socket_errno(s))); goto err; } + if (get_options()->ControlSocketsGroupWritable) { + /* We need to use chmod; fchmod doesn't work on sockets on all + * platforms. */ + if (chmod(address, 0660) < 0) { + log_warn(LD_FS,"Unable to make %s group-writable.", address); + tor_close_socket(s); + goto err; + } + } if (listen(s,SOMAXCONN) < 0) { log_warn(LD_NET, "Could not listen on %s: %s", address, @@ -1011,7 +1092,7 @@ connection_create_listener(struct sockaddr *listensockaddr, socklen_t socklen, conn->socket_family = listensockaddr->sa_family; conn->s = s; conn->address = tor_strdup(address); - conn->port = usePort; + conn->port = gotPort; if (connection_add(conn) < 0) { /* no space, forget it */ log_warn(LD_NET,"connection_add for listener failed. Giving up."); @@ -1019,8 +1100,12 @@ connection_create_listener(struct sockaddr *listensockaddr, socklen_t socklen, goto err; } - log_debug(LD_NET,"%s listening on port %u.", - conn_type_to_string(type), usePort); + log_fn(usePort==gotPort ? LOG_DEBUG : LOG_NOTICE, LD_NET, + "%s listening on port %u.", + conn_type_to_string(type), gotPort); + + if (type == CONN_TYPE_CONTROL_LISTENER) + control_ports_write_to_file(); conn->state = LISTENER_STATE_READY; if (start_reading) { @@ -1100,20 +1185,20 @@ check_sockaddr_family_match(sa_family_t got, connection_t *listener) static int connection_handle_listener_read(connection_t *conn, int new_type) { - int news; /* the new socket */ + tor_socket_t news; /* the new socket */ connection_t *newconn; /* information about the remote peer when connecting to other routers */ char addrbuf[256]; struct sockaddr *remote = (struct sockaddr*)addrbuf; /* length of the remote address. Must be whatever accept() needs. */ socklen_t remotelen = (socklen_t)sizeof(addrbuf); - or_options_t *options = get_options(); + const or_options_t *options = get_options(); tor_assert((size_t)remotelen >= sizeof(struct sockaddr_in)); memset(addrbuf, 0, sizeof(addrbuf)); news = tor_accept_socket(conn->s,remote,&remotelen); - if (news < 0) { /* accept() error */ + if (!SOCKET_OK(news)) { /* accept() error */ int e = tor_socket_errno(conn->s); if (ERRNO_IS_ACCEPT_EAGAIN(e)) { return 0; /* he hung up before we could accept(). that's fine. */ @@ -1129,8 +1214,9 @@ connection_handle_listener_read(connection_t *conn, int new_type) } log_debug(LD_NET, "Connection accepted on socket %d (child of fd %d).", - news,conn->s); + (int)news,(int)conn->s); + make_socket_reuseable(news); set_socket_nonblocking(news); if (options->ConstrainedSockets) @@ -1281,11 +1367,12 @@ int connection_connect(connection_t *conn, const char *address, const tor_addr_t *addr, uint16_t port, int *socket_error) { - int s, inprogress = 0; + tor_socket_t s; + int inprogress = 0; char addrbuf[256]; struct sockaddr *dest_addr; int dest_addr_len; - or_options_t *options = get_options(); + const or_options_t *options = get_options(); int protocol_family; if (get_n_open_sockets() >= get_options()->_ConnLimit-1) { @@ -1340,6 +1427,8 @@ connection_connect(connection_t *conn, const char *address, log_debug(LD_NET, "Connecting to %s:%u.", escaped_safe_str_client(address), port); + make_socket_reuseable(s); + if (connect(s, dest_addr, (socklen_t)dest_addr_len) < 0) { int e = tor_socket_errno(s); if (!ERRNO_IS_CONN_EINPROGRESS(e)) { @@ -1406,7 +1495,7 @@ connection_proxy_state_to_string(int state) int connection_proxy_connect(connection_t *conn, int type) { - or_options_t *options; + const or_options_t *options; tor_assert(conn); @@ -1547,10 +1636,20 @@ connection_read_https_proxy_response(connection_t *conn) return 1; } /* else, bad news on the status code */ - log_warn(LD_NET, - "The https proxy sent back an unexpected status code %d (%s). " - "Closing.", - status_code, escaped(reason)); + switch (status_code) { + case 403: + log_warn(LD_NET, + "The https proxy refused to allow connection to %s " + "(status code %d, %s). Closing.", + conn->address, status_code, escaped(reason)); + break; + default: + log_warn(LD_NET, + "The https proxy sent back an unexpected status code %d (%s). " + "Closing.", + status_code, escaped(reason)); + break; + } tor_free(reason); return -1; } @@ -1799,10 +1898,23 @@ retry_listeners(int type, config_line_t *cfg, if (!parse_addr_port(LOG_WARN, wanted->value, &address, NULL, &port)) { int addr_matches = !strcasecmp(address, conn->address); + int port_matches; tor_free(address); - if (! port) - port = port_option; - if (port == conn->port && addr_matches) { + if (port) { + /* The Listener line has a port */ + port_matches = (port == conn->port); + } else if (port_option == CFG_AUTO_PORT) { + /* The Listener line has no port, and the Port line is "auto". + * "auto" matches anything; transitions from any port to + * "auto" succeed. */ + port_matches = 1; + } else { + /* The Listener line has no port, and the Port line is "auto". + * "auto" matches anything; transitions from any port to + * "auto" succeed. */ + port_matches = (port_option == conn->port); + } + if (port_matches && addr_matches) { line = wanted; break; } @@ -1850,7 +1962,7 @@ retry_listeners(int type, config_line_t *cfg, case AF_INET: listensockaddr = (struct sockaddr *) create_inet_sockaddr(cfg_line->value, - (uint16_t) port_option, + port_option, &address, &listensocklen); break; case AF_UNIX: @@ -1899,38 +2011,41 @@ int retry_all_listeners(smartlist_t *replaced_conns, smartlist_t *new_conns) { - or_options_t *options = get_options(); + const or_options_t *options = get_options(); + int retval = 0; + const uint16_t old_or_port = router_get_advertised_or_port(options); + const uint16_t old_dir_port = router_get_advertised_dir_port(options, 0); if (retry_listeners(CONN_TYPE_OR_LISTENER, options->ORListenAddress, options->ORPort, "0.0.0.0", replaced_conns, new_conns, options->ClientOnly, AF_INET)<0) - return -1; + retval = -1; if (retry_listeners(CONN_TYPE_DIR_LISTENER, options->DirListenAddress, options->DirPort, "0.0.0.0", replaced_conns, new_conns, options->ClientOnly, AF_INET)<0) - return -1; + retval = -1; if (retry_listeners(CONN_TYPE_AP_LISTENER, options->SocksListenAddress, options->SocksPort, "127.0.0.1", replaced_conns, new_conns, 0, AF_INET)<0) - return -1; + retval = -1; if (retry_listeners(CONN_TYPE_AP_TRANS_LISTENER, options->TransListenAddress, options->TransPort, "127.0.0.1", replaced_conns, new_conns, 0, AF_INET)<0) - return -1; + retval = -1; if (retry_listeners(CONN_TYPE_AP_NATD_LISTENER, options->NATDListenAddress, options->NATDPort, "127.0.0.1", replaced_conns, new_conns, 0, AF_INET)<0) - return -1; + retval = -1; if (retry_listeners(CONN_TYPE_AP_DNS_LISTENER, options->DNSListenAddress, options->DNSPort, "127.0.0.1", replaced_conns, new_conns, 0, AF_INET)<0) - return -1; + retval = -1; if (retry_listeners(CONN_TYPE_CONTROL_LISTENER, options->ControlListenAddress, options->ControlPort, "127.0.0.1", @@ -1944,7 +2059,16 @@ retry_all_listeners(smartlist_t *replaced_conns, AF_UNIX)<0) return -1; - return 0; + if (old_or_port != router_get_advertised_or_port(options) || + old_dir_port != router_get_advertised_dir_port(options, 0)) { + /* Our chosen ORPort or DirPort is not what it used to be: the + * descriptor we had (if any) should be regenerated. (We won't + * automatically notice this because of changes in the option, + * since the value could be "auto".) */ + mark_my_descriptor_dirty("Chosen Or/DirPort changed"); + } + + return retval; } /** Return 1 if we should apply rate limiting to <b>conn</b>, @@ -1953,7 +2077,7 @@ retry_all_listeners(smartlist_t *replaced_conns, static int connection_is_rate_limited(connection_t *conn) { - or_options_t *options = get_options(); + const or_options_t *options = get_options(); if (conn->linked) return 0; /* Internal connection */ else if (! options->CountPrivateBandwidth && @@ -2151,7 +2275,7 @@ global_write_bucket_low(connection_t *conn, size_t attempt, int priority) if (priority == 1) { /* old-style v1 query */ /* Could we handle *two* of these requests within the next two seconds? */ - or_options_t *options = get_options(); + const or_options_t *options = get_options(); int64_t can_write = (int64_t)smaller_bucket + 2*(options->RelayBandwidthRate ? options->RelayBandwidthRate : options->BandwidthRate); @@ -2269,7 +2393,7 @@ connection_consider_empty_write_buckets(connection_t *conn) void connection_bucket_init(void) { - or_options_t *options = get_options(); + const or_options_t *options = get_options(); /* start it at max traffic */ global_read_bucket = (int)options->BandwidthBurst; global_write_bucket = (int)options->BandwidthBurst; @@ -2314,7 +2438,7 @@ connection_bucket_refill_helper(int *bucket, int rate, int burst, void connection_bucket_refill(int seconds_elapsed, time_t now) { - or_options_t *options = get_options(); + const or_options_t *options = get_options(); smartlist_t *conns = get_connection_array(); int relayrate, relayburst; @@ -2377,7 +2501,7 @@ connection_bucket_refill(int seconds_elapsed, time_t now) TO_OR_CONN(conn)->read_bucket > 0)) { /* and either a non-cell conn or a cell conn with non-empty bucket */ LOG_FN_CONN(conn, (LOG_DEBUG,LD_NET, - "waking up conn (fd %d) for read", conn->s)); + "waking up conn (fd %d) for read", (int)conn->s)); conn->read_blocked_on_bw = 0; connection_start_reading(conn); } @@ -2390,7 +2514,7 @@ connection_bucket_refill(int seconds_elapsed, time_t now) conn->state != OR_CONN_STATE_OPEN || TO_OR_CONN(conn)->write_bucket > 0)) { LOG_FN_CONN(conn, (LOG_DEBUG,LD_NET, - "waking up conn (fd %d) for write", conn->s)); + "waking up conn (fd %d) for write", (int)conn->s)); conn->write_blocked_on_bw = 0; connection_start_writing(conn); } @@ -2434,7 +2558,7 @@ connection_bucket_refill(int seconds_elapsed, time_t now) void connection_bucket_init(void) { - or_options_t *options = get_options(); + const or_options_t *options = get_options(); const struct timeval *tick = tor_libevent_get_one_tick_timeout(); struct ev_token_bucket_cfg *bucket_cfg; @@ -2664,7 +2788,7 @@ connection_read_to_buf(connection_t *conn, ssize_t *max_to_read, log_debug(LD_NET, "%d: starting, inbuf_datalen %ld (%d pending in tls object)." " at_most %ld.", - conn->s,(long)buf_datalen(conn->inbuf), + (int)conn->s,(long)buf_datalen(conn->inbuf), tor_tls_get_pending_bytes(or_conn->tls), (long)at_most); initial_size = buf_datalen(conn->inbuf); @@ -2833,9 +2957,11 @@ connection_handle_read_cb(struct bufferevent *bufev, void *arg) { connection_t *conn = arg; (void) bufev; - if (!conn->marked_for_close) + if (!conn->marked_for_close) { if (connection_process_inbuf(conn, 1)<0) /* XXXX Always 1? */ - connection_mark_for_close(conn); + if (!conn->marked_for_close) + connection_mark_for_close(conn); + } } /** Callback: invoked whenever a bufferevent has written data. */ @@ -2845,7 +2971,8 @@ connection_handle_write_cb(struct bufferevent *bufev, void *arg) connection_t *conn = arg; struct evbuffer *output; if (connection_flushed_some(conn)<0) { - connection_mark_for_close(conn); + if (!conn->marked_for_close) + connection_mark_for_close(conn); return; } @@ -2996,15 +3123,15 @@ connection_outbuf_too_full(connection_t *conn) return (conn->outbuf_flushlen > 10*CELL_PAYLOAD_SIZE); } -/** Try to flush more bytes onto conn-\>s. +/** Try to flush more bytes onto <b>conn</b>-\>s. * * This function gets called either from conn_write() in main.c * when poll() has declared that conn wants to write, or below * from connection_write_to_buf() when an entire TLS record is ready. * - * Update conn-\>timestamp_lastwritten to now, and call flush_buf + * Update <b>conn</b>-\>timestamp_lastwritten to now, and call flush_buf * or flush_buf_tls appropriately. If it succeeds and there are no more - * more bytes on conn->outbuf, then call connection_finished_flushing + * more bytes on <b>conn</b>-\>outbuf, then call connection_finished_flushing * on it too. * * If <b>force</b>, then write as many bytes as possible, ignoring bandwidth @@ -3026,7 +3153,7 @@ connection_handle_write_impl(connection_t *conn, int force) tor_assert(!connection_is_listener(conn)); - if (conn->marked_for_close || conn->s < 0) + if (conn->marked_for_close || !SOCKET_OK(conn->s)) return 0; /* do nothing */ if (conn->in_flushed_some) { @@ -3196,6 +3323,25 @@ connection_handle_write(connection_t *conn, int force) return res; } +/** + * Try to flush data that's waiting for a write on <b>conn</b>. Return + * -1 on failure, 0 on success. + * + * Don't use this function for regular writing; the buffers/bufferevents + * system should be good enough at scheduling writes there. Instead, this + * function is for cases when we're about to exit or something and we want + * to report it right away. + */ +int +connection_flush(connection_t *conn) +{ + IF_HAS_BUFFEREVENT(conn, { + int r = bufferevent_flush(conn->bufev, EV_WRITE, BEV_FLUSH); + return (r < 0) ? -1 : 0; + }); + return connection_handle_write(conn, 1); +} + /** OpenSSL TLS record size is 16383; this is close. The goal here is to * push data out as soon as we know there's enough for a TLS record, so * during periods of high load we won't read entire megabytes from @@ -3260,12 +3406,13 @@ _connection_write_to_buf_impl(const char *string, size_t len, /* if it failed, it means we have our package/delivery windows set wrong compared to our max outbuf size. close the whole circuit. */ log_warn(LD_NET, - "write_to_buf failed. Closing circuit (fd %d).", conn->s); + "write_to_buf failed. Closing circuit (fd %d).", (int)conn->s); circuit_mark_for_close(circuit_get_by_edge_conn(TO_EDGE_CONN(conn)), END_CIRC_REASON_INTERNAL); } else { log_warn(LD_NET, - "write_to_buf failed. Closing connection (fd %d).", conn->s); + "write_to_buf failed. Closing connection (fd %d).", + (int)conn->s); connection_mark_for_close(conn); } return; @@ -3311,7 +3458,7 @@ _connection_write_to_buf_impl(const char *string, size_t len, /* this connection is broken. remove it. */ log_warn(LD_BUG, "unhandled error on write for " "conn (type %d, fd %d); removing", - conn->type, conn->s); + conn->type, (int)conn->s); tor_fragile_assert(); /* do a close-immediate here, so we don't try to flush */ connection_close_immediate(conn); @@ -3539,8 +3686,17 @@ alloc_http_authenticator(const char *authenticator) authenticator, authenticator_length) < 0) { tor_free(base64_authenticator); /* free and set to null */ } else { - /* remove extra \n at end of encoding */ - base64_authenticator[strlen(base64_authenticator) - 1] = 0; + int i = 0, j = 0; + ssize_t len = strlen(base64_authenticator); + + /* remove all newline occurrences within the string */ + for (i=0; i < len; ++i) { + if ('\n' != base64_authenticator[i]) { + base64_authenticator[j] = base64_authenticator[i]; + ++j; + } + } + base64_authenticator[j]='\0'; } return base64_authenticator; } @@ -3551,7 +3707,7 @@ alloc_http_authenticator(const char *authenticator) * call init_keys(). */ static void -client_check_address_changed(int sock) +client_check_address_changed(tor_socket_t sock) { uint32_t iface_ip, ip_out; /* host order */ struct sockaddr_in out_addr; @@ -3607,7 +3763,7 @@ client_check_address_changed(int sock) * to the desired size to stay below system TCP buffer limits. */ static void -set_constrained_socket_buffers(int sock, int size) +set_constrained_socket_buffers(tor_socket_t sock, int size) { void *sz = (void*)&size; socklen_t sz_sz = (socklen_t) sizeof(size); @@ -3852,7 +4008,7 @@ assert_connection_ok(connection_t *conn, time_t now) tor_assert(conn->linked); } if (conn->linked) - tor_assert(conn->s < 0); + tor_assert(!SOCKET_OK(conn->s)); if (conn->outbuf_flushlen > 0) { /* With optimistic data, we may have queued data in diff --git a/src/or/connection.h b/src/or/connection.h index 94ae64591..8dc011209 100644 --- a/src/or/connection.h +++ b/src/or/connection.h @@ -79,6 +79,8 @@ int connection_fetch_from_buf_http(connection_t *conn, int connection_wants_to_flush(connection_t *conn); int connection_outbuf_too_full(connection_t *conn); int connection_handle_write(connection_t *conn, int force); +int connection_flush(connection_t *conn); + void _connection_write_to_buf_impl(const char *string, size_t len, connection_t *conn, int zlib); static void connection_write_to_buf(const char *string, size_t len, diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c index 4e45cbeff..c49014848 100644 --- a/src/or/connection_edge.c +++ b/src/or/connection_edge.c @@ -439,7 +439,7 @@ connection_ap_expire_beginning(void) edge_connection_t *conn; circuit_t *circ; time_t now = time(NULL); - or_options_t *options = get_options(); + const or_options_t *options = get_options(); int severity; int cutoff; int seconds_idle, seconds_since_born; @@ -503,12 +503,12 @@ connection_ap_expire_beginning(void) } tor_assert(circ->purpose == CIRCUIT_PURPOSE_C_GENERAL); log_fn(cutoff < 15 ? LOG_INFO : severity, LD_APP, - "We tried for %d seconds to connect to '%s' using exit '%s'." + "We tried for %d seconds to connect to '%s' using exit %s." " Retrying on a new circuit.", seconds_idle, safe_str_client(conn->socks_request->address), conn->cpath_layer ? - conn->cpath_layer->extend_info->nickname : "*unnamed*"); + extend_info_describe(conn->cpath_layer->extend_info): "*unnamed*"); /* send an end down the circuit */ connection_edge_end(conn, END_STREAM_REASON_TIMEOUT); /* un-mark it as ending, since we're going to reuse it */ @@ -577,7 +577,7 @@ connection_ap_fail_onehop(const char *failed_digest, if (!edge_conn->want_onehop) continue; if (hexdigest_to_digest(edge_conn->chosen_exit_name, digest) < 0 || - memcmp(digest, failed_digest, DIGEST_LEN)) + tor_memneq(digest, failed_digest, DIGEST_LEN)) continue; if (tor_digest_is_zero(digest)) { /* we don't know the digest; have to compare addr:port */ @@ -810,9 +810,10 @@ clear_trackexithost_mappings(const char *exitname) } /** Remove all TRACKEXIT mappings from the addressmap for which the target - * host is unknown or no longer allowed. */ + * host is unknown or no longer allowed, or for which the source address + * is no longer in trackexithosts. */ void -addressmap_clear_excluded_trackexithosts(or_options_t *options) +addressmap_clear_excluded_trackexithosts(const or_options_t *options) { const routerset_t *allow_nodes = options->ExitNodes; const routerset_t *exclude_nodes = options->_ExcludeExitNodesUnion; @@ -851,7 +852,8 @@ addressmap_clear_excluded_trackexithosts(or_options_t *options) tor_free(nodename); if (!node || (allow_nodes && !routerset_contains_node(allow_nodes, node)) || - routerset_contains_node(exclude_nodes, node)) { + routerset_contains_node(exclude_nodes, node) || + !hostname_in_track_host_exits(options, address)) { /* We don't know this one, or we want to be rid of it. */ addressmap_ent_remove(address, ent); MAP_DEL_CURRENT(address); @@ -859,6 +861,49 @@ addressmap_clear_excluded_trackexithosts(or_options_t *options) } STRMAP_FOREACH_END; } +/** Remove all AUTOMAP mappings from the addressmap for which the + * source address no longer matches AutomapHostsSuffixes, which is + * no longer allowed by AutomapHostsOnResolve, or for which the + * target address is no longer in the virtual network. */ +void +addressmap_clear_invalid_automaps(const or_options_t *options) +{ + int clear_all = !options->AutomapHostsOnResolve; + const smartlist_t *suffixes = options->AutomapHostsSuffixes; + + if (!addressmap) + return; + + if (!suffixes) + clear_all = 1; /* This should be impossible, but let's be sure. */ + + STRMAP_FOREACH_MODIFY(addressmap, src_address, addressmap_entry_t *, ent) { + int remove = clear_all; + if (ent->source != ADDRMAPSRC_AUTOMAP) + continue; /* not an automap mapping. */ + + if (!remove) { + int suffix_found = 0; + SMARTLIST_FOREACH(suffixes, const char *, suffix, { + if (!strcasecmpend(src_address, suffix)) { + suffix_found = 1; + break; + } + }); + if (!suffix_found) + remove = 1; + } + + if (!remove && ! address_is_in_virtual_range(ent->new_address)) + remove = 1; + + if (remove) { + addressmap_ent_remove(src_address, ent); + MAP_DEL_CURRENT(src_address); + } + } STRMAP_FOREACH_END; +} + /** Remove all entries from the addressmap that were set via the * configuration file or the command line. */ void @@ -1370,7 +1415,7 @@ addressmap_register_virtual_address(int type, char *new_address) log_info(LD_APP, "Registering map from %s to %s", *addrp, new_address); if (vent_needs_to_be_added) strmap_set(virtaddress_reversemap, new_address, vent); - addressmap_register(*addrp, new_address, 2, ADDRMAPSRC_CONTROLLER); + addressmap_register(*addrp, new_address, 2, ADDRMAPSRC_AUTOMAP); #if 0 { @@ -1475,7 +1520,7 @@ addressmap_get_mappings(smartlist_t *sl, time_t min_expires, static int consider_plaintext_ports(edge_connection_t *conn, uint16_t port) { - or_options_t *options = get_options(); + const or_options_t *options = get_options(); int reject = smartlist_string_num_isin(options->RejectPlaintextPorts, port); if (smartlist_string_num_isin(options->WarnPlaintextPorts, port)) { @@ -1512,7 +1557,7 @@ connection_ap_rewrite_and_attach_if_allowed(edge_connection_t *conn, origin_circuit_t *circ, crypt_path_t *cpath) { - or_options_t *options = get_options(); + const or_options_t *options = get_options(); if (options->LeaveStreamsUnattached) { conn->_base.state = AP_CONN_STATE_CONTROLLER_WAIT; @@ -1543,7 +1588,7 @@ connection_ap_handshake_rewrite_and_attach(edge_connection_t *conn, { socks_request_t *socks = conn->socks_request; hostname_type_t addresstype; - or_options_t *options = get_options(); + const or_options_t *options = get_options(); struct in_addr addr_tmp; /* We set this to true if this is an address we should automatically * remap to a local address in VirtualAddrNetwork */ @@ -1785,7 +1830,7 @@ connection_ap_handshake_rewrite_and_attach(edge_connection_t *conn, if (r) { log_info(LD_APP, "Redirecting address %s to exit at enclave router %s", - safe_str_client(socks->address), node_get_nickname(r)); + safe_str_client(socks->address), node_describe(r)); /* use the hex digest, not nickname, in case there are two routers with this nickname */ conn->chosen_exit_name = @@ -2034,7 +2079,7 @@ connection_ap_handshake_process_socks(edge_connection_t *conn) { socks_request_t *socks; int sockshere; - or_options_t *options = get_options(); + const or_options_t *options = get_options(); tor_assert(conn); tor_assert(conn->_base.type == CONN_TYPE_AP); @@ -2575,7 +2620,8 @@ connection_ap_handshake_socks_resolved(edge_connection_t *conn, } connection_ap_handshake_socks_reply(conn, buf, replylen, (answer_type == RESOLVED_TYPE_IPV4 || - answer_type == RESOLVED_TYPE_IPV6) ? + answer_type == RESOLVED_TYPE_IPV6 || + answer_type == RESOLVED_TYPE_HOSTNAME) ? 0 : END_STREAM_REASON_RESOLVEFAILED); } @@ -2658,7 +2704,7 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ) char *address=NULL; uint16_t port; or_circuit_t *or_circ = NULL; - or_options_t *options = get_options(); + const or_options_t *options = get_options(); assert_circuit_ok(circ); if (!CIRCUIT_IS_ORIGIN(circ)) @@ -3059,7 +3105,7 @@ connection_edge_is_rendezvous_stream(edge_connection_t *conn) int connection_ap_can_use_exit(edge_connection_t *conn, const node_t *exit) { - or_options_t *options = get_options(); + const or_options_t *options = get_options(); tor_assert(conn); tor_assert(conn->_base.type == CONN_TYPE_AP); @@ -3072,7 +3118,7 @@ connection_ap_can_use_exit(edge_connection_t *conn, const node_t *exit) if (conn->chosen_exit_name) { const node_t *chosen_exit = node_get_by_nickname(conn->chosen_exit_name, 1); - if (!chosen_exit || memcmp(chosen_exit->identity, + if (!chosen_exit || tor_memneq(chosen_exit->identity, exit->identity, DIGEST_LEN)) { /* doesn't match */ // log_debug(LD_APP,"Requested node '%s', considering node '%s'. No.", diff --git a/src/or/connection_edge.h b/src/or/connection_edge.h index 562db5b68..a7fc12e23 100644 --- a/src/or/connection_edge.h +++ b/src/or/connection_edge.h @@ -63,7 +63,8 @@ int connection_ap_process_transparent(edge_connection_t *conn); int address_is_invalid_destination(const char *address, int client); void addressmap_init(void); -void addressmap_clear_excluded_trackexithosts(or_options_t *options); +void addressmap_clear_excluded_trackexithosts(const or_options_t *options); +void addressmap_clear_invalid_automaps(const or_options_t *options); void addressmap_clean(time_t now); void addressmap_clear_configured(void); void addressmap_clear_transient(void); diff --git a/src/or/connection_or.c b/src/or/connection_or.c index 1f2575ae1..679500dee 100644 --- a/src/or/connection_or.c +++ b/src/or/connection_or.c @@ -124,7 +124,7 @@ connection_or_set_identity_digest(or_connection_t *conn, const char *digest) if (!orconn_identity_map) orconn_identity_map = digestmap_new(); - if (!memcmp(conn->identity_digest, digest, DIGEST_LEN)) + if (tor_memeq(conn->identity_digest, digest, DIGEST_LEN)) return; /* If the identity was set previously, remove the old mapping. */ @@ -143,7 +143,7 @@ connection_or_set_identity_digest(or_connection_t *conn, const char *digest) #if 1 /* Testing code to check for bugs in representation. */ for (; tmp; tmp = tmp->next_with_same_id) { - tor_assert(!memcmp(tmp->identity_digest, digest, DIGEST_LEN)); + tor_assert(tor_memeq(tmp->identity_digest, digest, DIGEST_LEN)); tor_assert(tmp != conn); } #endif @@ -380,7 +380,7 @@ connection_or_digest_is_known_relay(const char *id_digest) */ static void connection_or_update_token_buckets_helper(or_connection_t *conn, int reset, - or_options_t *options) + const or_options_t *options) { int rate, burst; /* per-connection rate limiting params */ if (connection_or_digest_is_known_relay(conn->identity_digest)) { @@ -436,7 +436,8 @@ connection_or_update_token_buckets_helper(or_connection_t *conn, int reset, * Go through all the OR connections and update their token buckets to make * sure they don't exceed their maximum values. */ void -connection_or_update_token_buckets(smartlist_t *conns, or_options_t *options) +connection_or_update_token_buckets(smartlist_t *conns, + const or_options_t *options) { SMARTLIST_FOREACH(conns, connection_t *, conn, { @@ -585,7 +586,7 @@ connection_or_get_for_extend(const char *digest, for (; conn; conn = conn->next_with_same_id) { tor_assert(conn->_base.magic == OR_CONNECTION_MAGIC); tor_assert(conn->_base.type == CONN_TYPE_OR); - tor_assert(!memcmp(conn->identity_digest, digest, DIGEST_LEN)); + tor_assert(tor_memeq(conn->identity_digest, digest, DIGEST_LEN)); if (conn->_base.marked_for_close) continue; /* Never return a non-open connection. */ @@ -788,7 +789,7 @@ connection_or_set_bad_connections(const char *digest, int force) return; DIGESTMAP_FOREACH(orconn_identity_map, identity, or_connection_t *, conn) { - if (!digest || !memcmp(digest, conn->identity_digest, DIGEST_LEN)) + if (!digest || tor_memeq(digest, conn->identity_digest, DIGEST_LEN)) connection_or_group_set_badness(conn, force); } DIGESTMAP_FOREACH_END; } @@ -827,7 +828,7 @@ connection_or_connect(const tor_addr_t *_addr, uint16_t port, const char *id_digest) { or_connection_t *conn; - or_options_t *options = get_options(); + const or_options_t *options = get_options(); int socket_error = 0; int using_proxy = 0; tor_addr_t addr; @@ -996,13 +997,16 @@ connection_tls_continue_handshake(or_connection_t *conn) if (! tor_tls_used_v1_handshake(conn->tls)) { if (!tor_tls_is_server(conn->tls)) { if (conn->_base.state == OR_CONN_STATE_TLS_HANDSHAKING) { - // log_notice(LD_OR,"Done. state was TLS_HANDSHAKING."); + log_debug(LD_OR, "Done with initial SSL handshake (client-side). " + "Requesting renegotiation."); conn->_base.state = OR_CONN_STATE_TLS_CLIENT_RENEGOTIATING; goto again; } // log_notice(LD_OR,"Done. state was %d.", conn->_base.state); } else { /* improved handshake, but not a client. */ + log_debug(LD_OR, "Done with initial SSL handshake (server-side). " + "Expecting renegotiation."); tor_tls_set_renegotiate_callback(conn->tls, connection_or_tls_renegotiated_cb, conn); @@ -1144,7 +1148,7 @@ connection_or_check_valid_tls_handshake(or_connection_t *conn, char *digest_rcvd_out) { crypto_pk_env_t *identity_rcvd=NULL; - or_options_t *options = get_options(); + const or_options_t *options = get_options(); int severity = server_mode(options) ? LOG_PROTOCOL_WARN : LOG_WARN; const char *safe_address = started_here ? conn->_base.address : @@ -1221,7 +1225,7 @@ connection_or_check_valid_tls_handshake(or_connection_t *conn, int as_advertised = 1; tor_assert(has_cert); tor_assert(has_identity); - if (memcmp(digest_rcvd_out, conn->identity_digest, DIGEST_LEN)) { + if (tor_memneq(digest_rcvd_out, conn->identity_digest, DIGEST_LEN)) { /* I was aiming for a particular digest. I didn't get it! */ char seen[HEX_DIGEST_LEN+1]; char expected[HEX_DIGEST_LEN+1]; diff --git a/src/or/connection_or.h b/src/or/connection_or.h index 70ef96a33..4a374cac0 100644 --- a/src/or/connection_or.h +++ b/src/or/connection_or.h @@ -27,7 +27,7 @@ int connection_or_finished_flushing(or_connection_t *conn); int connection_or_finished_connecting(or_connection_t *conn); int connection_or_digest_is_known_relay(const char *id_digest); void connection_or_update_token_buckets(smartlist_t *conns, - or_options_t *options); + const or_options_t *options); void connection_or_connect_failed(or_connection_t *conn, int reason, const char *msg); diff --git a/src/or/control.c b/src/or/control.c index 0aada5730..6ea9dbe47 100644 --- a/src/or/control.c +++ b/src/or/control.c @@ -38,6 +38,8 @@ #include <sys/resource.h> #endif +#include "procmon.h" + /** Yield true iff <b>s</b> is the state of a control_connection_t that has * finished authentication and is accepting commands. */ #define STATE_IS_OPEN(s) ((s) == CONTROL_CONN_STATE_OPEN) @@ -103,7 +105,7 @@ static int disable_log_messages = 0; static int authentication_cookie_is_set = 0; /** If authentication_cookie_is_set, a secret cookie that we've stored to disk * and which we're using to authenticate controllers. (If the controller can - * read it off disk, it has permission to connect. */ + * read it off disk, it has permission to connect.) */ static char authentication_cookie[AUTHENTICATION_COOKIE_LEN]; /** A sufficiently large size to record the last bootstrap phase string. */ @@ -341,7 +343,7 @@ write_escaped_data(const char *data, size_t len, char **out) } *outp++ = *data++; } - if (outp < *out+2 || memcmp(outp-2, "\r\n", 2)) { + if (outp < *out+2 || fast_memcmp(outp-2, "\r\n", 2)) { *outp++ = '\r'; *outp++ = '\n'; } @@ -486,33 +488,73 @@ decode_escaped_string(const char *start, size_t in_len_max, } /** Acts like sprintf, but writes its formatted string to the end of - * <b>conn</b>-\>outbuf. The message may be truncated if it is too long, - * but it will always end with a CRLF sequence. - * - * Currently the length of the message is limited to 1024 (including the - * ending CR LF NUL ("\\r\\n\\0"). */ + * <b>conn</b>-\>outbuf. */ static void connection_printf_to_buf(control_connection_t *conn, const char *format, ...) { -#define CONNECTION_PRINTF_TO_BUF_BUFFERSIZE 1024 va_list ap; - char buf[CONNECTION_PRINTF_TO_BUF_BUFFERSIZE]; - int r; - size_t len; + char *buf = NULL; + int len; + va_start(ap,format); - r = tor_vsnprintf(buf, sizeof(buf), format, ap); + len = tor_vasprintf(&buf, format, ap); va_end(ap); - if (r<0) { + + if (len < 0) { log_warn(LD_BUG, "Unable to format string for controller."); return; } - len = strlen(buf); - if (memcmp("\r\n\0", buf+len-2, 3)) { - buf[CONNECTION_PRINTF_TO_BUF_BUFFERSIZE-1] = '\0'; - buf[CONNECTION_PRINTF_TO_BUF_BUFFERSIZE-2] = '\n'; - buf[CONNECTION_PRINTF_TO_BUF_BUFFERSIZE-3] = '\r'; + + connection_write_to_buf(buf, (size_t)len, TO_CONN(conn)); + + tor_free(buf); +} + +/** Write all of the open control ports to ControlPortWriteToFile */ +void +control_ports_write_to_file(void) +{ + smartlist_t *lines; + char *joined = NULL; + const or_options_t *options = get_options(); + + if (!options->ControlPortWriteToFile) + return; + + lines = smartlist_create(); + + SMARTLIST_FOREACH_BEGIN(get_connection_array(), const connection_t *, conn) { + char *port_str = NULL; + if (conn->type != CONN_TYPE_CONTROL_LISTENER || conn->marked_for_close) + continue; +#ifdef AF_UNIX + if (conn->socket_family == AF_UNIX) { + tor_asprintf(&port_str, "UNIX_PORT=%s\n", conn->address); + smartlist_add(lines, port_str); + continue; + } +#endif + tor_asprintf(&port_str, "PORT=%s:%d\n", conn->address, conn->port); + smartlist_add(lines, port_str); + } SMARTLIST_FOREACH_END(conn); + + joined = smartlist_join_strings(lines, "", 0, NULL); + + if (write_str_to_file(options->ControlPortWriteToFile, joined, 0) < 0) { + log_warn(LD_CONTROL, "Writing %s failed: %s", + options->ControlPortWriteToFile, strerror(errno)); + } +#ifndef MS_WINDOWS + if (options->ControlPortFileGroupReadable) { + if (chmod(options->ControlPortWriteToFile, 0640)) { + log_warn(LD_FS,"Unable to make %s group-readable.", + options->ControlPortWriteToFile); + } } - connection_write_to_buf(buf, len, TO_CONN(conn)); +#endif + tor_free(joined); + SMARTLIST_FOREACH(lines, char *, cp, tor_free(cp)); + smartlist_free(lines); } /** Send a "DONE" message down the control connection <b>conn</b>. */ @@ -558,52 +600,37 @@ send_control_event_string(uint16_t event, event_format_t which, else if (event == EVENT_STATUS_SERVER) is_err = !strcmpstart(msg, "STATUS_SERVER ERR "); if (is_err) - connection_handle_write(TO_CONN(control_conn), 1); + connection_flush(TO_CONN(control_conn)); } } } SMARTLIST_FOREACH_END(conn); } -/** Helper for send_control1_event and send_control1_event_extended: +/** Helper for send_control_event and control_event_status: * Send an event to all v1 controllers that are listening for code * <b>event</b>. The event's body is created by the printf-style format in - * <b>format</b>, and other arguments as provided. - * - * Currently the length of the message is limited to 1024 (including the - * ending \\r\\n\\0). */ + * <b>format</b>, and other arguments as provided. */ static void send_control_event_impl(uint16_t event, event_format_t which, const char *format, va_list ap) { - /* This is just a little longer than the longest allowed log message */ -#define SEND_CONTROL1_EVENT_BUFFERSIZE 10064 - int r; - char buf[SEND_CONTROL1_EVENT_BUFFERSIZE]; - size_t len; + char *buf = NULL; + int len; - r = tor_vsnprintf(buf, sizeof(buf), format, ap); - if (r<0) { + len = tor_vasprintf(&buf, format, ap); + if (len < 0) { log_warn(LD_BUG, "Unable to format event for controller."); return; } - len = strlen(buf); - if (memcmp("\r\n\0", buf+len-2, 3)) { - /* if it is not properly terminated, do it now */ - buf[SEND_CONTROL1_EVENT_BUFFERSIZE-1] = '\0'; - buf[SEND_CONTROL1_EVENT_BUFFERSIZE-2] = '\n'; - buf[SEND_CONTROL1_EVENT_BUFFERSIZE-3] = '\r'; - } - send_control_event_string(event, which|ALL_FORMATS, buf); + + tor_free(buf); } /** Send an event to all v1 controllers that are listening for code * <b>event</b>. The event's body is created by the printf-style format in - * <b>format</b>, and other arguments as provided. - * - * Currently the length of the message is limited to 1024 (including the - * ending \\n\\r\\0. */ + * <b>format</b>, and other arguments as provided. */ static void send_control_event(uint16_t event, event_format_t which, const char *format, ...) @@ -778,7 +805,7 @@ handle_control_getconf(control_connection_t *conn, uint32_t body_len, smartlist_t *unrecognized = smartlist_create(); char *msg = NULL; size_t msg_len; - or_options_t *options = get_options(); + const or_options_t *options = get_options(); int i, len; (void) body_len; /* body is NUL-terminated; so we can ignore len. */ @@ -890,13 +917,44 @@ handle_control_loadconf(control_connection_t *conn, uint32_t len, return 0; } +struct control_event_t { + uint16_t event_code; + const char *event_name; +}; +static const struct control_event_t control_event_table[] = { + { EVENT_CIRCUIT_STATUS, "CIRC" }, + { EVENT_STREAM_STATUS, "STREAM" }, + { EVENT_OR_CONN_STATUS, "ORCONN" }, + { EVENT_BANDWIDTH_USED, "BW" }, + { EVENT_DEBUG_MSG, "DEBUG" }, + { EVENT_INFO_MSG, "INFO" }, + { EVENT_NOTICE_MSG, "NOTICE" }, + { EVENT_WARN_MSG, "WARN" }, + { EVENT_ERR_MSG, "ERR" }, + { EVENT_NEW_DESC, "NEWDESC" }, + { EVENT_ADDRMAP, "ADDRMAP" }, + { EVENT_AUTHDIR_NEWDESCS, "AUTHDIR_NEWDESCS" }, + { EVENT_DESCCHANGED, "DESCCHANGED" }, + { EVENT_NS, "NS" }, + { EVENT_STATUS_GENERAL, "STATUS_GENERAL" }, + { EVENT_STATUS_CLIENT, "STATUS_CLIENT" }, + { EVENT_STATUS_SERVER, "STATUS_SERVER" }, + { EVENT_GUARD, "GUARD" }, + { EVENT_STREAM_BANDWIDTH_USED, "STREAM_BW" }, + { EVENT_CLIENTS_SEEN, "CLIENTS_SEEN" }, + { EVENT_NEWCONSENSUS, "NEWCONSENSUS" }, + { EVENT_BUILDTIMEOUT_SET, "BUILDTIMEOUT_SET" }, + { EVENT_SIGNAL, "SIGNAL" }, + { 0, NULL }, +}; + /** Called when we get a SETEVENTS message: update conn->event_mask, * and reply with DONE or ERROR. */ static int handle_control_setevents(control_connection_t *conn, uint32_t len, const char *body) { - uint16_t event_code; + int event_code = -1; uint32_t event_mask = 0; smartlist_t *events = smartlist_create(); @@ -908,58 +966,22 @@ handle_control_setevents(control_connection_t *conn, uint32_t len, { if (!strcasecmp(ev, "EXTENDED")) { continue; - } else if (!strcasecmp(ev, "CIRC")) - event_code = EVENT_CIRCUIT_STATUS; - else if (!strcasecmp(ev, "STREAM")) - event_code = EVENT_STREAM_STATUS; - else if (!strcasecmp(ev, "ORCONN")) - event_code = EVENT_OR_CONN_STATUS; - else if (!strcasecmp(ev, "BW")) - event_code = EVENT_BANDWIDTH_USED; - else if (!strcasecmp(ev, "DEBUG")) - event_code = EVENT_DEBUG_MSG; - else if (!strcasecmp(ev, "INFO")) - event_code = EVENT_INFO_MSG; - else if (!strcasecmp(ev, "NOTICE")) - event_code = EVENT_NOTICE_MSG; - else if (!strcasecmp(ev, "WARN")) - event_code = EVENT_WARN_MSG; - else if (!strcasecmp(ev, "ERR")) - event_code = EVENT_ERR_MSG; - else if (!strcasecmp(ev, "NEWDESC")) - event_code = EVENT_NEW_DESC; - else if (!strcasecmp(ev, "ADDRMAP")) - event_code = EVENT_ADDRMAP; - else if (!strcasecmp(ev, "AUTHDIR_NEWDESCS")) - event_code = EVENT_AUTHDIR_NEWDESCS; - else if (!strcasecmp(ev, "DESCCHANGED")) - event_code = EVENT_DESCCHANGED; - else if (!strcasecmp(ev, "NS")) - event_code = EVENT_NS; - else if (!strcasecmp(ev, "STATUS_GENERAL")) - event_code = EVENT_STATUS_GENERAL; - else if (!strcasecmp(ev, "STATUS_CLIENT")) - event_code = EVENT_STATUS_CLIENT; - else if (!strcasecmp(ev, "STATUS_SERVER")) - event_code = EVENT_STATUS_SERVER; - else if (!strcasecmp(ev, "GUARD")) - event_code = EVENT_GUARD; - else if (!strcasecmp(ev, "STREAM_BW")) - event_code = EVENT_STREAM_BANDWIDTH_USED; - else if (!strcasecmp(ev, "CLIENTS_SEEN")) - event_code = EVENT_CLIENTS_SEEN; - else if (!strcasecmp(ev, "NEWCONSENSUS")) - event_code = EVENT_NEWCONSENSUS; - else if (!strcasecmp(ev, "BUILDTIMEOUT_SET")) - event_code = EVENT_BUILDTIMEOUT_SET; - else if (!strcasecmp(ev, "SIGNAL")) - event_code = EVENT_SIGNAL; - else { - connection_printf_to_buf(conn, "552 Unrecognized event \"%s\"\r\n", - ev); - SMARTLIST_FOREACH(events, char *, e, tor_free(e)); - smartlist_free(events); - return 0; + } else { + int i; + for (i = 0; control_event_table[i].event_name != NULL; ++i) { + if (!strcasecmp(ev, control_event_table[i].event_name)) { + event_code = control_event_table[i].event_code; + break; + } + } + + if (event_code == -1) { + connection_printf_to_buf(conn, "552 Unrecognized event \"%s\"\r\n", + ev); + SMARTLIST_FOREACH(events, char *, e, tor_free(e)); + smartlist_free(events); + return 0; + } } event_mask |= (1 << event_code); } @@ -1021,7 +1043,7 @@ handle_control_authenticate(control_connection_t *conn, uint32_t len, const char *body) { int used_quoted_string = 0; - or_options_t *options = get_options(); + const or_options_t *options = get_options(); const char *errstr = NULL; char *password; size_t password_len; @@ -1078,7 +1100,7 @@ handle_control_authenticate(control_connection_t *conn, uint32_t len, goto err; } bad_cookie = 1; - } else if (memcmp(authentication_cookie, password, password_len)) { + } else if (tor_memneq(authentication_cookie, password, password_len)) { if (!also_password) { log_warn(LD_CONTROL, "Got mismatched authentication cookie"); errstr = "Authentication cookie did not match expected value."; @@ -1128,7 +1150,7 @@ handle_control_authenticate(control_connection_t *conn, uint32_t len, SMARTLIST_FOREACH(sl, char *, expected, { secret_to_key(received,DIGEST_LEN,password,password_len,expected); - if (!memcmp(expected+S2K_SPECIFIER_LEN, received, DIGEST_LEN)) + if (tor_memeq(expected+S2K_SPECIFIER_LEN, received, DIGEST_LEN)) goto ok; }); SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp)); @@ -1230,13 +1252,33 @@ handle_control_signal(control_connection_t *conn, uint32_t len, send_control_done(conn); /* Flush the "done" first if the signal might make us shut down. */ if (sig == SIGTERM || sig == SIGINT) - connection_handle_write(TO_CONN(conn), 1); + connection_flush(TO_CONN(conn)); process_signal(sig); return 0; } +/** Called when we get a TAKEOWNERSHIP command. Mark this connection + * as an owning connection, so that we will exit if the connection + * closes. */ +static int +handle_control_takeownership(control_connection_t *conn, uint32_t len, + const char *body) +{ + (void)len; + (void)body; + + conn->is_owning_control_connection = 1; + + log_info(LD_CONTROL, "Control connection %d has taken ownership of this " + "Tor instance.", + (int)(conn->_base.s)); + + send_control_done(conn); + return 0; +} + /** Called when we get a MAPADDRESS command; try to bind all listed addresses, * and report success or failure. */ static int @@ -1339,10 +1381,16 @@ getinfo_helper_misc(control_connection_t *conn, const char *question, } else if (!strcmp(question, "info/names")) { *answer = list_getinfo_options(); } else if (!strcmp(question, "events/names")) { - *answer = tor_strdup("CIRC STREAM ORCONN BW DEBUG INFO NOTICE WARN ERR " - "NEWDESC ADDRMAP AUTHDIR_NEWDESCS DESCCHANGED " - "NS STATUS_GENERAL STATUS_CLIENT STATUS_SERVER " - "GUARD STREAM_BW CLIENTS_SEEN NEWCONSENSUS"); + int i; + smartlist_t *event_names = smartlist_create(); + + for (i = 0; control_event_table[i].event_name != NULL; ++i) { + smartlist_add(event_names, (char *)control_event_table[i].event_name); + } + + *answer = smartlist_join_strings(event_names, " ", 0, NULL); + + smartlist_free(event_names); } else if (!strcmp(question, "features/names")) { *answer = tor_strdup("VERBOSE_NAMES EXTENDED_EVENTS"); } else if (!strcmp(question, "address")) { @@ -1472,6 +1520,63 @@ munge_extrainfo_into_routerinfo(const char *ri_body, return tor_strndup(ri_body, ri->signed_descriptor_len); } +/** Implementation helper for GETINFO: answers requests for information about + * which ports are bound. */ +static int +getinfo_helper_listeners(control_connection_t *control_conn, + const char *question, + char **answer, const char **errmsg) +{ + int type; + smartlist_t *res; + + (void)control_conn; + (void)errmsg; + + if (!strcmp(question, "net/listeners/or")) + type = CONN_TYPE_OR_LISTENER; + else if (!strcmp(question, "net/listeners/dir")) + type = CONN_TYPE_DIR_LISTENER; + else if (!strcmp(question, "net/listeners/socks")) + type = CONN_TYPE_AP_LISTENER; + else if (!strcmp(question, "net/listeners/trans")) + type = CONN_TYPE_AP_TRANS_LISTENER; + else if (!strcmp(question, "net/listeners/natd")) + type = CONN_TYPE_AP_NATD_LISTENER; + else if (!strcmp(question, "net/listeners/dns")) + type = CONN_TYPE_AP_DNS_LISTENER; + else if (!strcmp(question, "net/listeners/control")) + type = CONN_TYPE_CONTROL_LISTENER; + else + return 0; /* unknown key */ + + res = smartlist_create(); + SMARTLIST_FOREACH_BEGIN(get_connection_array(), connection_t *, conn) { + char *addr; + struct sockaddr_storage ss; + socklen_t ss_len = sizeof(ss); + + if (conn->type != type || conn->marked_for_close || !SOCKET_OK(conn->s)) + continue; + + if (getsockname(conn->s, (struct sockaddr *)&ss, &ss_len) < 0) { + tor_asprintf(&addr, "%s:%d", conn->address, (int)conn->port); + } else { + char *tmp = tor_sockaddr_to_str((struct sockaddr *)&ss); + addr = esc_for_log(tmp); + tor_free(tmp); + } + if (addr) + smartlist_add(res, addr); + } SMARTLIST_FOREACH_END(conn); + + *answer = smartlist_join_strings(res, " ", 0, NULL); + + SMARTLIST_FOREACH(res, char *, cp, tor_free(cp)); + smartlist_free(res); + return 0; +} + /** Implementation helper for GETINFO: knows the answers for questions about * directory information. */ static int @@ -1927,6 +2032,7 @@ static const getinfo_item_t getinfo_items[] = { "All non-expired, non-superseded router descriptors."), ITEM("desc/all-recent-extrainfo-hack", dir, NULL), /* Hack. */ PREFIX("extra-info/digest/", dir, "Extra-info documents by digest."), + PREFIX("net/listeners/", listeners, "Bound addresses by type"), ITEM("ns/all", networkstatus, "Brief summary of router status (v2 directory format)"), PREFIX("ns/id/", networkstatus, @@ -1979,8 +2085,8 @@ static const getinfo_item_t getinfo_items[] = { "v2 networkstatus docs as retrieved from a DirPort."), ITEM("dir/status-vote/current/consensus", dir, "v3 Networkstatus consensus as retrieved from a DirPort."), - PREFIX("exit-policy/default", policies, - "The default value appended to the configured exit policy."), + ITEM("exit-policy/default", policies, + "The default value appended to the configured exit policy."), PREFIX("ip-to-country/", geoip, "Perform a GEOIP lookup"), { NULL, NULL, NULL, 0 } }; @@ -2722,7 +2828,7 @@ handle_control_protocolinfo(control_connection_t *conn, uint32_t len, connection_mark_for_close(TO_CONN(conn)); goto done; } else { - or_options_t *options = get_options(); + const or_options_t *options = get_options(); int cookies = options->CookieAuthentication; char *cfile = get_cookie_file(); char *esc_cfile = esc_for_log(cfile); @@ -2814,6 +2920,43 @@ connection_control_reached_eof(control_connection_t *conn) return 0; } +/** Shut down this Tor instance in the same way that SIGINT would, but + * with a log message appropriate for the loss of an owning controller. */ +static void +lost_owning_controller(const char *owner_type, const char *loss_manner) +{ + int shutdown_slowly = server_mode(get_options()); + + log_notice(LD_CONTROL, "Owning controller %s has %s -- %s.", + owner_type, loss_manner, + shutdown_slowly ? "shutting down" : "exiting now"); + + /* XXXX Perhaps this chunk of code should be a separate function, + * called here and by process_signal(SIGINT). */ + + if (!shutdown_slowly) { + tor_cleanup(); + exit(0); + } + /* XXXX This will close all listening sockets except control-port + * listeners. Perhaps we should close those too. */ + hibernate_begin_shutdown(); +} + +/** Called when <b>conn</b> is being freed. */ +void +connection_control_closed(control_connection_t *conn) +{ + tor_assert(conn); + + conn->event_mask = 0; + control_update_global_event_mask(); + + if (conn->is_owning_control_connection) { + lost_owning_controller("connection", "closed"); + } +} + /** Return true iff <b>cmd</b> is allowable (or at least forgivable) at this * stage of the protocol. */ static int @@ -2921,13 +3064,13 @@ connection_control_process_inbuf(control_connection_t *conn) break; /* XXXX this code duplication is kind of dumb. */ if (last_idx+3 == conn->incoming_cmd_cur_len && - !memcmp(conn->incoming_cmd + last_idx, ".\r\n", 3)) { + tor_memeq(conn->incoming_cmd + last_idx, ".\r\n", 3)) { /* Just appended ".\r\n"; we're done. Remove it. */ conn->incoming_cmd[last_idx] = '\0'; conn->incoming_cmd_cur_len -= 3; break; } else if (last_idx+2 == conn->incoming_cmd_cur_len && - !memcmp(conn->incoming_cmd + last_idx, ".\n", 2)) { + tor_memeq(conn->incoming_cmd + last_idx, ".\n", 2)) { /* Just appended ".\n"; we're done. Remove it. */ conn->incoming_cmd[last_idx] = '\0'; conn->incoming_cmd_cur_len -= 2; @@ -2978,6 +3121,9 @@ connection_control_process_inbuf(control_connection_t *conn) return 0; } + /* XXXX Why is this not implemented as a table like the GETINFO + * items are? Even handling the plus signs at the beginnings of + * commands wouldn't be very hard with proper macros. */ cmd_data_len = (uint32_t)data_len; if (!strcasecmp(conn->incoming_cmd, "SETCONF")) { if (handle_control_setconf(conn, cmd_data_len, args)) @@ -3003,6 +3149,9 @@ connection_control_process_inbuf(control_connection_t *conn) } else if (!strcasecmp(conn->incoming_cmd, "SIGNAL")) { if (handle_control_signal(conn, cmd_data_len, args)) return -1; + } else if (!strcasecmp(conn->incoming_cmd, "TAKEOWNERSHIP")) { + if (handle_control_takeownership(conn, cmd_data_len, args)) + return -1; } else if (!strcasecmp(conn->incoming_cmd, "MAPADDRESS")) { if (handle_control_mapaddress(conn, cmd_data_len, args)) return -1; @@ -3058,7 +3207,6 @@ control_event_circuit_status(origin_circuit_t *circ, circuit_status_event_t tp, { const char *status; char extended_buf[96]; - int providing_reason=0; if (!EVENT_IS_INTERESTING(EVENT_CIRCUIT_STATUS)) return 0; tor_assert(circ); @@ -3082,7 +3230,6 @@ control_event_circuit_status(origin_circuit_t *circ, circuit_status_event_t tp, const char *reason_str = circuit_end_reason_to_control_string(reason_code); char *reason = NULL; size_t n=strlen(extended_buf); - providing_reason=1; if (!reason_str) { reason = tor_malloc(16); tor_snprintf(reason, 16, "UNKNOWN_%d", reason_code); @@ -3853,7 +4000,7 @@ control_event_guard(const char *nickname, const char *digest, static char * get_cookie_file(void) { - or_options_t *options = get_options(); + const or_options_t *options = get_options(); if (options->CookieAuthFile && strlen(options->CookieAuthFile)) { return tor_strdup(options->CookieAuthFile); } else { @@ -3901,6 +4048,75 @@ init_cookie_authentication(int enabled) return 0; } +/** A copy of the process specifier of Tor's owning controller, or + * NULL if this Tor instance is not currently owned by a process. */ +static char *owning_controller_process_spec = NULL; + +/** A process-termination monitor for Tor's owning controller, or NULL + * if this Tor instance is not currently owned by a process. */ +static tor_process_monitor_t *owning_controller_process_monitor = NULL; + +/** Process-termination monitor callback for Tor's owning controller + * process. */ +static void +owning_controller_procmon_cb(void *unused) +{ + (void)unused; + + lost_owning_controller("process", "vanished"); +} + +/** Set <b>process_spec</b> as Tor's owning controller process. + * Exit on failure. */ +void +monitor_owning_controller_process(const char *process_spec) +{ + const char *msg; + + tor_assert((owning_controller_process_spec == NULL) == + (owning_controller_process_monitor == NULL)); + + if (owning_controller_process_spec != NULL) { + if ((process_spec != NULL) && !strcmp(process_spec, + owning_controller_process_spec)) { + /* Same process -- return now, instead of disposing of and + * recreating the process-termination monitor. */ + return; + } + + /* We are currently owned by a process, and we should no longer be + * owned by it. Free the process-termination monitor. */ + tor_process_monitor_free(owning_controller_process_monitor); + owning_controller_process_monitor = NULL; + + tor_free(owning_controller_process_spec); + owning_controller_process_spec = NULL; + } + + tor_assert((owning_controller_process_spec == NULL) && + (owning_controller_process_monitor == NULL)); + + if (process_spec == NULL) + return; + + owning_controller_process_spec = tor_strdup(process_spec); + owning_controller_process_monitor = + tor_process_monitor_new(tor_libevent_get_base(), + owning_controller_process_spec, + LD_CONTROL, + owning_controller_procmon_cb, NULL, + &msg); + + if (owning_controller_process_monitor == NULL) { + log_err(LD_BUG, "Couldn't create process-termination monitor for " + "owning controller: %s. Exiting.", + msg); + owning_controller_process_spec = NULL; + tor_cleanup(); + exit(0); + } +} + /** Convert the name of a bootstrapping phase <b>s</b> into strings * <b>tag</b> and <b>summary</b> suitable for display by the controller. */ static int diff --git a/src/or/control.h b/src/or/control.h index bec067792..147a5af0b 100644 --- a/src/or/control.h +++ b/src/or/control.h @@ -15,6 +15,8 @@ void control_update_global_event_mask(void); void control_adjust_event_log_severity(void); +void control_ports_write_to_file(void); + /** Log information about the connection <b>conn</b>, protecting it as with * CONN_LOG_PROTECT. Example: * @@ -25,6 +27,8 @@ void control_adjust_event_log_severity(void); int connection_control_finished_flushing(control_connection_t *conn); int connection_control_reached_eof(control_connection_t *conn); +void connection_control_closed(control_connection_t *conn); + int connection_control_process_inbuf(control_connection_t *conn); #define EVENT_AUTHDIR_NEWDESCS 0x000D @@ -71,6 +75,8 @@ smartlist_t *decode_hashed_passwords(config_line_t *passwords); void disable_control_logging(void); void enable_control_logging(void); +void monitor_owning_controller_process(const char *process_spec); + void control_event_bootstrap(bootstrap_status_t status, int progress); void control_event_bootstrap_problem(const char *warn, int reason); diff --git a/src/or/cpuworker.c b/src/or/cpuworker.c index 5597cad2a..bf8964c29 100644 --- a/src/or/cpuworker.c +++ b/src/or/cpuworker.c @@ -225,8 +225,8 @@ cpuworker_main(void *data) { char question[ONIONSKIN_CHALLENGE_LEN]; uint8_t question_type; - int *fdarray = data; - int fd; + tor_socket_t *fdarray = data; + tor_socket_t fd; /* variables for onion processing */ char keys[CPATH_KEY_MATERIAL_LEN]; @@ -316,12 +316,12 @@ cpuworker_main(void *data) static int spawn_cpuworker(void) { - int *fdarray; - int fd; + tor_socket_t *fdarray; + tor_socket_t fd; connection_t *conn; int err; - fdarray = tor_malloc(sizeof(int)*2); + fdarray = tor_malloc(sizeof(tor_socket_t)*2); if ((err = tor_socketpair(AF_UNIX, SOCK_STREAM, 0, fdarray)) < 0) { log_warn(LD_NET, "Couldn't construct socketpair for cpuworker: %s", tor_socket_strerror(-err)); diff --git a/src/or/directory.c b/src/or/directory.c index 2821619ce..9e1373d46 100644 --- a/src/or/directory.c +++ b/src/or/directory.c @@ -252,7 +252,7 @@ int directories_have_accepted_server_descriptor(void) { smartlist_t *servers = router_get_trusted_dir_servers(); - or_options_t *options = get_options(); + const or_options_t *options = get_options(); SMARTLIST_FOREACH(servers, trusted_dir_server_t *, d, { if ((d->type & options->_PublishServerDescriptor) && d->has_accepted_serverdesc) { @@ -285,10 +285,12 @@ directory_post_to_dirservers(uint8_t dir_purpose, uint8_t router_purpose, const char *payload, size_t payload_len, size_t extrainfo_len) { - or_options_t *options = get_options(); + const or_options_t *options = get_options(); int post_via_tor; smartlist_t *dirservers = router_get_trusted_dir_servers(); int found = 0; + const int exclude_self = (dir_purpose == DIR_PURPOSE_UPLOAD_VOTE || + dir_purpose == DIR_PURPOSE_UPLOAD_SIGNATURES); tor_assert(dirservers); /* This tries dirservers which we believe to be down, but ultimately, that's * harmless, and we may as well err on the side of getting things uploaded. @@ -301,6 +303,9 @@ directory_post_to_dirservers(uint8_t dir_purpose, uint8_t router_purpose, if ((type & ds->type) == 0) continue; + if (exclude_self && router_digest_is_me(ds->digest)) + continue; + if (options->ExcludeNodes && options->StrictNodes && routerset_contains_routerstatus(options->ExcludeNodes, rs, -1)) { log_warn(LD_DIR, "Wanted to contact authority '%s' for %s, but " @@ -347,7 +352,7 @@ directory_get_from_dirserver(uint8_t dir_purpose, uint8_t router_purpose, const char *resource, int pds_flags) { const routerstatus_t *rs = NULL; - or_options_t *options = get_options(); + const or_options_t *options = get_options(); int prefer_authority = directory_fetches_from_authorities(options); int get_via_tor = purpose_needs_anonymity(dir_purpose, router_purpose); dirinfo_type_t type; @@ -543,7 +548,7 @@ directory_initiate_command_routerstatus_rend(const routerstatus_t *status, time_t if_modified_since, const rend_data_t *rend_query) { - or_options_t *options = get_options(); + const or_options_t *options = get_options(); const node_t *node; char address_buf[INET_NTOA_BUF_LEN+1]; struct in_addr in; @@ -553,7 +558,8 @@ directory_initiate_command_routerstatus_rend(const routerstatus_t *status, if (!node && anonymized_connection) { log_info(LD_DIR, "Not sending anonymized request to directory '%s'; we " - "don't have its router descriptor.", status->nickname); + "don't have its router descriptor.", + routerstatus_describe(status)); return; } else if (node) { node_get_address_string(node, address_buf, sizeof(address_buf)); @@ -567,10 +573,10 @@ directory_initiate_command_routerstatus_rend(const routerstatus_t *status, if (options->ExcludeNodes && options->StrictNodes && routerset_contains_routerstatus(options->ExcludeNodes, status, -1)) { - log_warn(LD_DIR, "Wanted to contact directory mirror '%s' for %s, but " + log_warn(LD_DIR, "Wanted to contact directory mirror %s for %s, but " "it's in our ExcludedNodes list and StrictNodes is set. " "Skipping. This choice might make your Tor not work.", - status->nickname, + routerstatus_describe(status), dir_conn_purpose_to_string(dir_purpose)); return; } @@ -811,7 +817,7 @@ connection_dir_download_cert_failed(dir_connection_t *conn, int status) * 3) Else yes. */ static int -directory_command_should_use_begindir(or_options_t *options, +directory_command_should_use_begindir(const or_options_t *options, const tor_addr_t *addr, int or_port, uint8_t router_purpose, int anonymized_connection) @@ -852,6 +858,20 @@ directory_initiate_command(const char *address, const tor_addr_t *_addr, if_modified_since, NULL); } +/** Return non-zero iff a directory connection with purpose + * <b>dir_purpose</b> reveals sensitive information about a Tor + * instance's client activities. (Such connections must be performed + * through normal three-hop Tor circuits.) */ +static int +is_sensitive_dir_purpose(uint8_t dir_purpose) +{ + return ((dir_purpose == DIR_PURPOSE_FETCH_RENDDESC) || + (dir_purpose == DIR_PURPOSE_HAS_FETCHED_RENDDESC) || + (dir_purpose == DIR_PURPOSE_UPLOAD_RENDDESC) || + (dir_purpose == DIR_PURPOSE_UPLOAD_RENDDESC_V2) || + (dir_purpose == DIR_PURPOSE_FETCH_RENDDESC_V2)); +} + /** Same as directory_initiate_command(), but accepts rendezvous data to * fetch a hidden service descriptor. */ static void @@ -867,7 +887,7 @@ directory_initiate_command_rend(const char *address, const tor_addr_t *_addr, const rend_data_t *rend_query) { dir_connection_t *conn; - or_options_t *options = get_options(); + const or_options_t *options = get_options(); int socket_error = 0; int use_begindir = supports_begindir && directory_command_should_use_begindir(options, _addr, @@ -886,6 +906,9 @@ directory_initiate_command_rend(const char *address, const tor_addr_t *_addr, log_debug(LD_DIR, "Initiating %s", dir_conn_purpose_to_string(dir_purpose)); + tor_assert(!(is_sensitive_dir_purpose(dir_purpose) && + !anonymized_connection)); + /* ensure that we don't make direct connections when a SOCKS server is * configured. */ if (!anonymized_connection && !use_begindir && !options->HTTPProxy && @@ -2000,7 +2023,6 @@ connection_dir_client_reached_eof(dir_connection_t *conn) router_get_trusteddirserver_by_digest(conn->identity_digest); char *rejected_hdr = http_get_header(headers, "X-Descriptor-Not-New: "); - int rejected = 0; if (rejected_hdr) { if (!strcmp(rejected_hdr, "Yes")) { log_info(LD_GENERAL, @@ -2013,7 +2035,6 @@ connection_dir_client_reached_eof(dir_connection_t *conn) * last descriptor, not on the published time of the last * descriptor. If those are different, that's a bad thing to * do. -NM */ - rejected = 1; } tor_free(rejected_hdr); } @@ -2103,7 +2124,8 @@ connection_dir_client_reached_eof(dir_connection_t *conn) (int)body_len, status_code, escaped(reason)); switch (status_code) { case 200: - if (rend_cache_store(body, body_len, 0) < -1) { + if (rend_cache_store(body, body_len, 0, + conn->rend_data->onion_address) < -1) { log_warn(LD_REND,"Failed to parse rendezvous descriptor."); /* Any pending rendezvous attempts will notice when * connection_about_to_close_connection() @@ -2547,7 +2569,7 @@ client_likes_consensus(networkstatus_t *v, const char *want_url) SMARTLIST_FOREACH_BEGIN(v->voters, networkstatus_voter_info_t *, vi) { if (smartlist_len(vi->sigs) && - !memcmp(vi->identity_digest, want_digest, want_len)) { + tor_memeq(vi->identity_digest, want_digest, want_len)) { have++; break; }; @@ -2570,18 +2592,18 @@ client_likes_consensus(networkstatus_t *v, const char *want_url) * Always return 0. */ static int directory_handle_command_get(dir_connection_t *conn, const char *headers, - const char *body, size_t body_len) + const char *req_body, size_t req_body_len) { size_t dlen; char *url, *url_mem, *header; - or_options_t *options = get_options(); + const or_options_t *options = get_options(); time_t if_modified_since = 0; int compressed; size_t url_len; /* We ignore the body of a GET request. */ - (void)body; - (void)body_len; + (void)req_body; + (void)req_body_len; log_debug(LD_DIRSERV,"Received GET command."); @@ -3290,7 +3312,7 @@ directory_handle_command_post(dir_connection_t *conn, const char *headers, const char *body, size_t body_len) { char *url = NULL; - or_options_t *options = get_options(); + const or_options_t *options = get_options(); log_debug(LD_DIRSERV,"Received POST command."); @@ -3371,7 +3393,7 @@ directory_handle_command_post(dir_connection_t *conn, const char *headers, !strcmpstart(url,"/tor/rendezvous/publish")) { /* rendezvous descriptor post */ log_info(LD_REND, "Handling rendezvous descriptor post."); - if (rend_cache_store(body, body_len, 1) < 0) { + if (rend_cache_store(body, body_len, 1, NULL) < 0) { log_fn(LOG_PROTOCOL_WARN, LD_DIRSERV, "Rejected rend descriptor (length %d) from %s.", (int)body_len, conn->_base.address); @@ -3750,17 +3772,17 @@ dir_microdesc_download_failed(smartlist_t *failed, } SMARTLIST_FOREACH_END(d); } -/** Helper. Compare two fp_pair_t objects, and return -1, 0, or 1 as - * appropriate. */ +/** Helper. Compare two fp_pair_t objects, and return negative, 0, or + * positive as appropriate. */ static int _compare_pairs(const void **a, const void **b) { const fp_pair_t *fp1 = *a, *fp2 = *b; int r; - if ((r = memcmp(fp1->first, fp2->first, DIGEST_LEN))) + if ((r = fast_memcmp(fp1->first, fp2->first, DIGEST_LEN))) return r; else - return memcmp(fp1->second, fp2->second, DIGEST_LEN); + return fast_memcmp(fp1->second, fp2->second, DIGEST_LEN); } /** Divide a string <b>res</b> of the form FP1-FP2+FP3-FP4...[.z], where each diff --git a/src/or/dirserv.c b/src/or/dirserv.c index 0ac2d804c..0ea1ef648 100644 --- a/src/or/dirserv.c +++ b/src/or/dirserv.c @@ -212,7 +212,7 @@ dirserv_load_fingerprint_file(void) authdir_config_t *fingerprint_list_new; int result; config_line_t *front=NULL, *list; - or_options_t *options = get_options(); + const or_options_t *options = get_options(); fname = get_datadir_fname("approved-routers"); log_info(LD_GENERAL, @@ -518,14 +518,15 @@ dirserv_router_has_valid_address(routerinfo_t *ri) if (get_options()->DirAllowPrivateAddresses) return 0; /* whatever it is, we're fine with it */ if (!tor_inet_aton(ri->address, &iaddr)) { - log_info(LD_DIRSERV,"Router '%s' published non-IP address '%s'. Refusing.", - ri->nickname, ri->address); + log_info(LD_DIRSERV,"Router %s published non-IP address '%s'. Refusing.", + router_describe(ri), + ri->address); return -1; } if (is_internal_IP(ntohl(iaddr.s_addr), 0)) { log_info(LD_DIRSERV, - "Router '%s' published internal IP address '%s'. Refusing.", - ri->nickname, ri->address); + "Router %s published internal IP address '%s'. Refusing.", + router_describe(ri), ri->address); return -1; /* it's a private IP, we should reject it */ } return 0; @@ -554,10 +555,11 @@ authdir_wants_to_reject_router(routerinfo_t *ri, const char **msg, /* Is there too much clock skew? */ now = time(NULL); if (ri->cache_info.published_on > now+ROUTER_ALLOW_SKEW) { - log_fn(severity, LD_DIRSERV, "Publication time for nickname '%s' is too " + log_fn(severity, LD_DIRSERV, "Publication time for %s is too " "far (%d minutes) in the future; possible clock skew. Not adding " "(%s)", - ri->nickname, (int)((ri->cache_info.published_on-now)/60), + router_describe(ri), + (int)((ri->cache_info.published_on-now)/60), esc_router_info(ri)); *msg = "Rejected: Your clock is set too far in the future, or your " "timezone is not correct."; @@ -565,9 +567,10 @@ authdir_wants_to_reject_router(routerinfo_t *ri, const char **msg, } if (ri->cache_info.published_on < now-ROUTER_MAX_AGE_TO_PUBLISH) { log_fn(severity, LD_DIRSERV, - "Publication time for router with nickname '%s' is too far " + "Publication time for %s is too far " "(%d minutes) in the past. Not adding (%s)", - ri->nickname, (int)((now-ri->cache_info.published_on)/60), + router_describe(ri), + (int)((now-ri->cache_info.published_on)/60), esc_router_info(ri)); *msg = "Rejected: Server is expired, or your clock is too far in the past," " or your timezone is not correct."; @@ -575,9 +578,10 @@ authdir_wants_to_reject_router(routerinfo_t *ri, const char **msg, } if (dirserv_router_has_valid_address(ri) < 0) { log_fn(severity, LD_DIRSERV, - "Router with nickname '%s' has invalid address '%s'. " + "Router %s has invalid address '%s'. " "Not adding (%s).", - ri->nickname, ri->address, + router_describe(ri), + ri->address, esc_router_info(ri)); *msg = "Rejected: Address is not an IP, or IP is a private address."; return -1; @@ -729,9 +733,9 @@ dirserv_add_descriptor(routerinfo_t *ri, const char **msg, const char *source) && router_differences_are_cosmetic(ri_old, ri) && !router_is_me(ri)) { log_info(LD_DIRSERV, - "Not replacing descriptor from '%s' (source: %s); " + "Not replacing descriptor from %s (source: %s); " "differences are cosmetic.", - ri->nickname, source); + router_describe(ri), source); *msg = "Not replacing router descriptor; no information has changed since " "the last one with this identity."; control_event_or_authdir_new_descriptor("DROPPED", @@ -831,13 +835,15 @@ directory_remove_invalid(void) SMARTLIST_FOREACH_BEGIN(nodes, node_t *, node) { const char *msg; routerinfo_t *ent = node->ri; + char description[NODE_DESC_BUF_LEN]; uint32_t r; if (!ent) continue; r = dirserv_router_get_status(ent, &msg); + router_get_description(description, ent); if (r & FP_REJECT) { - log_info(LD_DIRSERV, "Router '%s' is now rejected: %s", - ent->nickname, msg?msg:""); + log_info(LD_DIRSERV, "Router %s is now rejected: %s", + description, msg?msg:""); routerlist_remove(rl, ent, 0, time(NULL)); changed = 1; continue; @@ -845,33 +851,33 @@ directory_remove_invalid(void) #if 0 if (bool_neq((r & FP_NAMED), ent->auth_says_is_named)) { log_info(LD_DIRSERV, - "Router '%s' is now %snamed.", ent->nickname, + "Router %s is now %snamed.", description, (r&FP_NAMED)?"":"un"); ent->is_named = (r&FP_NAMED)?1:0; changed = 1; } if (bool_neq((r & FP_UNNAMED), ent->auth_says_is_unnamed)) { log_info(LD_DIRSERV, - "Router '%s' is now %snamed. (FP_UNNAMED)", ent->nickname, + "Router '%s' is now %snamed. (FP_UNNAMED)", description, (r&FP_NAMED)?"":"un"); ent->is_named = (r&FP_NUNAMED)?0:1; changed = 1; } #endif if (bool_neq((r & FP_INVALID), !node->is_valid)) { - log_info(LD_DIRSERV, "Router '%s' is now %svalid.", ent->nickname, + log_info(LD_DIRSERV, "Router '%s' is now %svalid.", description, (r&FP_INVALID) ? "in" : ""); node->is_valid = (r&FP_INVALID)?0:1; changed = 1; } if (bool_neq((r & FP_BADDIR), node->is_bad_directory)) { - log_info(LD_DIRSERV, "Router '%s' is now a %s directory", ent->nickname, + log_info(LD_DIRSERV, "Router '%s' is now a %s directory", description, (r & FP_BADDIR) ? "bad" : "good"); node->is_bad_directory = (r&FP_BADDIR) ? 1: 0; changed = 1; } if (bool_neq((r & FP_BADEXIT), node->is_bad_exit)) { - log_info(LD_DIRSERV, "Router '%s' is now a %s exit", ent->nickname, + log_info(LD_DIRSERV, "Router '%s' is now a %s exit", description, (r & FP_BADEXIT) ? "bad" : "good"); node->is_bad_exit = (r&FP_BADEXIT) ? 1: 0; changed = 1; @@ -1026,7 +1032,7 @@ list_server_status_v1(smartlist_t *routers, char **router_status_out, smartlist_t *rs_entries; time_t now = time(NULL); time_t cutoff = now - ROUTER_MAX_AGE_TO_PUBLISH; - or_options_t *options = get_options(); + const or_options_t *options = get_options(); /* We include v2 dir auths here too, because they need to answer * controllers. Eventually we'll deprecate this whole function; * see also networkstatus_getinfo_by_purpose(). */ @@ -1193,7 +1199,7 @@ dirserv_dump_directory_to_string(char **dir_out, /** Return 1 if we fetch our directory material directly from the * authorities, rather than from a mirror. */ int -directory_fetches_from_authorities(or_options_t *options) +directory_fetches_from_authorities(const or_options_t *options) { const routerinfo_t *me; uint32_t addr; @@ -1220,7 +1226,7 @@ directory_fetches_from_authorities(or_options_t *options) * on the "mirror" schedule rather than the "client" schedule. */ int -directory_fetches_dir_info_early(or_options_t *options) +directory_fetches_dir_info_early(const or_options_t *options) { return directory_fetches_from_authorities(options); } @@ -1232,7 +1238,7 @@ directory_fetches_dir_info_early(or_options_t *options) * client as a directory guard. */ int -directory_fetches_dir_info_later(or_options_t *options) +directory_fetches_dir_info_later(const or_options_t *options) { return options->UseBridges != 0; } @@ -1240,7 +1246,7 @@ directory_fetches_dir_info_later(or_options_t *options) /** Return 1 if we want to cache v2 dir info (each status file). */ int -directory_caches_v2_dir_info(or_options_t *options) +directory_caches_v2_dir_info(const or_options_t *options) { return options->DirPort != 0; } @@ -1249,7 +1255,7 @@ directory_caches_v2_dir_info(or_options_t *options) * and we're willing to serve them to others. Else return 0. */ int -directory_caches_dir_info(or_options_t *options) +directory_caches_dir_info(const or_options_t *options) { if (options->BridgeRelay || options->DirPort) return 1; @@ -1265,7 +1271,7 @@ directory_caches_dir_info(or_options_t *options) * requests via the "begin_dir" interface, which doesn't require * having any separate port open. */ int -directory_permits_begindir_requests(or_options_t *options) +directory_permits_begindir_requests(const or_options_t *options) { return options->BridgeRelay != 0 || options->DirPort != 0; } @@ -1274,7 +1280,7 @@ directory_permits_begindir_requests(or_options_t *options) * requests via the controller interface, which doesn't require * having any separate port open. */ int -directory_permits_controller_requests(or_options_t *options) +directory_permits_controller_requests(const or_options_t *options) { return options->DirPort != 0; } @@ -1284,7 +1290,8 @@ directory_permits_controller_requests(or_options_t *options) * lately. */ int -directory_too_idle_to_fetch_descriptors(or_options_t *options, time_t now) +directory_too_idle_to_fetch_descriptors(const or_options_t *options, + time_t now) { return !directory_caches_dir_info(options) && !options->FetchUselessDescriptors && @@ -1554,7 +1561,7 @@ dirserv_pick_cached_dir_obj(cached_dir_t *cache_src, const char *name, dirinfo_type_t auth_type) { - or_options_t *options = get_options(); + const or_options_t *options = get_options(); int authority = (auth_type == V1_DIRINFO && authdir_mode_v1(options)) || (auth_type == V2_DIRINFO && authdir_mode_v2(options)); @@ -2116,7 +2123,7 @@ routerstatus_format_entry(char *buf, size_t buf_len, /* This assert can fire for the control port, because * it can request NS documents before all descriptors * have been fetched. */ - if (memcmp(desc->cache_info.signed_descriptor_digest, + if (tor_memneq(desc->cache_info.signed_descriptor_digest, rs->descriptor_digest, DIGEST_LEN)) { char rl_d[HEX_DIGEST_LEN+1]; @@ -2132,7 +2139,7 @@ routerstatus_format_entry(char *buf, size_t buf_len, "(router %s)\n", rl_d, rs_d, id); - tor_assert(!memcmp(desc->cache_info.signed_descriptor_digest, + tor_assert(tor_memeq(desc->cache_info.signed_descriptor_digest, rs->descriptor_digest, DIGEST_LEN)); }; @@ -2234,9 +2241,9 @@ _compare_routerinfo_by_ip_and_bw(const void **a, const void **b) /* They're equal! Compare by identity digest, so there's a * deterministic order and we avoid flapping. */ - return memcmp(first->cache_info.identity_digest, - second->cache_info.identity_digest, - DIGEST_LEN); + return fast_memcmp(first->cache_info.identity_digest, + second->cache_info.identity_digest, + DIGEST_LEN); } /** Given a list of routerinfo_t in <b>routers</b>, return a new digestmap_t @@ -2245,7 +2252,7 @@ _compare_routerinfo_by_ip_and_bw(const void **a, const void **b) static digestmap_t * get_possible_sybil_list(const smartlist_t *routers) { - or_options_t *options = get_options(); + const or_options_t *options = get_options(); digestmap_t *omit_as_sybil; smartlist_t *routers_by_ip = smartlist_create(); uint32_t last_addr; @@ -2433,7 +2440,7 @@ measured_bw_line_parse(measured_bw_line_t *out, const char *orig_line) tor_free(line); return -1; } - strncpy(out->node_hex, cp, sizeof(out->node_hex)); + strlcpy(out->node_hex, cp, sizeof(out->node_hex)); got_node_id=1; } } while ((cp = tor_strtok_r(NULL, " \t", &strtok_state))); @@ -2545,7 +2552,7 @@ networkstatus_t * dirserv_generate_networkstatus_vote_obj(crypto_pk_env_t *private_key, authority_cert_t *cert) { - or_options_t *options = get_options(); + const or_options_t *options = get_options(); networkstatus_t *v3_out = NULL; uint32_t addr; char *hostname = NULL, *client_versions = NULL, *server_versions = NULL; @@ -2726,8 +2733,8 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_env_t *private_key, voter->sigs = smartlist_create(); voter->address = hostname; voter->addr = addr; - voter->dir_port = options->DirPort; - voter->or_port = options->ORPort; + voter->dir_port = router_get_advertised_dir_port(options, 0); + voter->or_port = router_get_advertised_or_port(options); voter->contact = tor_strdup(contact); if (options->V3AuthUseLegacyKey) { authority_cert_t *c = get_my_v3_legacy_cert(); @@ -2760,7 +2767,7 @@ generate_v2_networkstatus_opinion(void) char *status = NULL, *client_versions = NULL, *server_versions = NULL, *identity_pkey = NULL, *hostname = NULL; char *outp, *endp; - or_options_t *options = get_options(); + const or_options_t *options = get_options(); char fingerprint[FINGERPRINT_LEN+1]; char published[ISO_TIME_LEN+1]; char digest[DIGEST_LEN]; @@ -2829,7 +2836,8 @@ generate_v2_networkstatus_opinion(void) "dir-options%s%s%s%s\n" "%s" /* client version line, server version line. */ "dir-signing-key\n%s", - hostname, fmt_addr32(addr), (int)options->DirPort, + hostname, fmt_addr32(addr), + (int)router_get_advertised_dir_port(options, 0), fingerprint, contact, published, @@ -3185,12 +3193,13 @@ dirserv_orconn_tls_done(const char *address, SMARTLIST_FOREACH_BEGIN(rl->routers, routerinfo_t *, ri) { if (!strcasecmp(address, ri->address) && or_port == ri->or_port && as_advertised && - !memcmp(ri->cache_info.identity_digest, digest_rcvd, DIGEST_LEN)) { + fast_memeq(ri->cache_info.identity_digest, digest_rcvd, DIGEST_LEN)) { /* correct digest. mark this router reachable! */ if (!bridge_auth || ri->purpose == ROUTER_PURPOSE_BRIDGE) { tor_addr_t addr, *addrp=NULL; log_info(LD_DIRSERV, "Found router %s to be reachable at %s:%d. Yay.", - ri->nickname, address, ri->or_port ); + router_describe(ri), + address, ri->or_port); if (tor_addr_from_str(&addr, ri->address) != -1) addrp = &addr; else diff --git a/src/or/dirserv.h b/src/or/dirserv.h index 8bd6d18f9..d3fd90ceb 100644 --- a/src/or/dirserv.h +++ b/src/or/dirserv.h @@ -71,15 +71,16 @@ int list_server_status_v1(smartlist_t *routers, char **router_status_out, int dirserv_dump_directory_to_string(char **dir_out, crypto_pk_env_t *private_key); -int directory_fetches_from_authorities(or_options_t *options); -int directory_fetches_dir_info_early(or_options_t *options); -int directory_fetches_dir_info_later(or_options_t *options); -int directory_caches_v2_dir_info(or_options_t *options); +int directory_fetches_from_authorities(const or_options_t *options); +int directory_fetches_dir_info_early(const or_options_t *options); +int directory_fetches_dir_info_later(const or_options_t *options); +int directory_caches_v2_dir_info(const or_options_t *options); #define directory_caches_v1_dir_info(o) directory_caches_v2_dir_info(o) -int directory_caches_dir_info(or_options_t *options); -int directory_permits_begindir_requests(or_options_t *options); -int directory_permits_controller_requests(or_options_t *options); -int directory_too_idle_to_fetch_descriptors(or_options_t *options, time_t now); +int directory_caches_dir_info(const or_options_t *options); +int directory_permits_begindir_requests(const or_options_t *options); +int directory_permits_controller_requests(const or_options_t *options); +int directory_too_idle_to_fetch_descriptors(const or_options_t *options, + time_t now); void directory_set_dirty(void); cached_dir_t *dirserv_get_directory(void); diff --git a/src/or/dirvote.c b/src/or/dirvote.c index fa0398c28..bf34c62af 100644 --- a/src/or/dirvote.c +++ b/src/or/dirvote.c @@ -337,7 +337,7 @@ static int _compare_votes_by_authority_id(const void **_a, const void **_b) { const networkstatus_t *a = *_a, *b = *_b; - return memcmp(get_voter(a)->identity_digest, + return fast_memcmp(get_voter(a)->identity_digest, get_voter(b)->identity_digest, DIGEST_LEN); } @@ -354,7 +354,7 @@ _compare_dir_src_ents_by_authority_id(const void **_a, const void **_b) a_id = a->is_legacy ? a_v->legacy_id_digest : a_v->identity_digest; b_id = b->is_legacy ? b_v->legacy_id_digest : b_v->identity_digest; - return memcmp(a_id, b_id, DIGEST_LEN); + return fast_memcmp(a_id, b_id, DIGEST_LEN); } /** Given a sorted list of strings <b>in</b>, add every member to <b>out</b> @@ -391,11 +391,12 @@ static int compare_vote_rs(const vote_routerstatus_t *a, const vote_routerstatus_t *b) { int r; - if ((r = memcmp(a->status.identity_digest, b->status.identity_digest, + if ((r = fast_memcmp(a->status.identity_digest, b->status.identity_digest, DIGEST_LEN))) return r; - if ((r = memcmp(a->status.descriptor_digest, b->status.descriptor_digest, - DIGEST_LEN))) + if ((r = fast_memcmp(a->status.descriptor_digest, + b->status.descriptor_digest, + DIGEST_LEN))) return r; if ((r = (int)(b->status.published_on - a->status.published_on))) return r; @@ -1584,7 +1585,7 @@ networkstatus_compute_consensus(smartlist_t *votes, * is the same flag as votes[j]->known_flags[b]. */ int *named_flag; /* Index of the flag "Named" for votes[j] */ int *unnamed_flag; /* Index of the flag "Unnamed" for votes[j] */ - int chosen_named_idx, chosen_unnamed_idx; + int chosen_named_idx; strmap_t *name_to_id_map = strmap_new(); char conflict[DIGEST_LEN]; @@ -1602,7 +1603,6 @@ networkstatus_compute_consensus(smartlist_t *votes, for (i = 0; i < smartlist_len(votes); ++i) unnamed_flag[i] = named_flag[i] = -1; chosen_named_idx = smartlist_string_pos(flags, "Named"); - chosen_unnamed_idx = smartlist_string_pos(flags, "Unnamed"); /* Build the flag index. */ SMARTLIST_FOREACH(votes, networkstatus_t *, v, @@ -1641,7 +1641,7 @@ networkstatus_compute_consensus(smartlist_t *votes, strmap_set_lc(name_to_id_map, rs->status.nickname, rs->status.identity_digest); } else if (d != conflict && - memcmp(d, rs->status.identity_digest, DIGEST_LEN)) { + fast_memcmp(d, rs->status.identity_digest, DIGEST_LEN)) { /* Authorities disagree about this nickname. */ strmap_set_lc(name_to_id_map, rs->status.nickname, conflict); } else { @@ -1665,7 +1665,7 @@ networkstatus_compute_consensus(smartlist_t *votes, } else if (!d) { /* We have no name officially mapped to this digest. */ strmap_set_lc(name_to_id_map, rs->status.nickname, unknown); - } else if (!memcmp(d, rs->status.identity_digest, DIGEST_LEN)) { + } else if (fast_memeq(d, rs->status.identity_digest, DIGEST_LEN)) { /* Authorities disagree about this nickname. */ strmap_set_lc(name_to_id_map, rs->status.nickname, conflict); } else { @@ -1698,7 +1698,8 @@ networkstatus_compute_consensus(smartlist_t *votes, if (index[v_sl_idx] < size[v_sl_idx]) { rs = smartlist_get(v->routerstatus_list, index[v_sl_idx]); if (!lowest_id || - memcmp(rs->status.identity_digest, lowest_id, DIGEST_LEN) < 0) + fast_memcmp(rs->status.identity_digest, + lowest_id, DIGEST_LEN) < 0) lowest_id = rs->status.identity_digest; } }); @@ -1717,7 +1718,7 @@ networkstatus_compute_consensus(smartlist_t *votes, if (index[v_sl_idx] >= size[v_sl_idx]) continue; /* out of entries. */ rs = smartlist_get(v->routerstatus_list, index[v_sl_idx]); - if (memcmp(rs->status.identity_digest, lowest_id, DIGEST_LEN)) + if (fast_memcmp(rs->status.identity_digest, lowest_id, DIGEST_LEN)) continue; /* doesn't include this router. */ /* At this point, we know that we're looking at a routerstatus with * identity "lowest". @@ -1762,7 +1763,7 @@ networkstatus_compute_consensus(smartlist_t *votes, rs = compute_routerstatus_consensus(matching_descs, consensus_method, microdesc_digest); /* Copy bits of that into rs_out. */ - tor_assert(!memcmp(lowest_id, rs->status.identity_digest, DIGEST_LEN)); + tor_assert(fast_memeq(lowest_id, rs->status.identity_digest,DIGEST_LEN)); memcpy(rs_out.identity_digest, lowest_id, DIGEST_LEN); memcpy(rs_out.descriptor_digest, rs->status.descriptor_digest, DIGEST_LEN); @@ -1786,7 +1787,7 @@ networkstatus_compute_consensus(smartlist_t *votes, const char *d = strmap_get_lc(name_to_id_map, rs_out.nickname); if (!d) { is_named = is_unnamed = 0; - } else if (!memcmp(d, lowest_id, DIGEST_LEN)) { + } else if (fast_memeq(d, lowest_id, DIGEST_LEN)) { is_named = 1; is_unnamed = 0; } else { is_named = 0; is_unnamed = 1; @@ -1884,11 +1885,11 @@ networkstatus_compute_consensus(smartlist_t *votes, SMARTLIST_FOREACH(matching_descs, vote_routerstatus_t *, vsr, { /* Check if the vote where this status comes from had the * proper descriptor */ - tor_assert(!memcmp(rs_out.identity_digest, + tor_assert(fast_memeq(rs_out.identity_digest, vsr->status.identity_digest, DIGEST_LEN)); if (vsr->status.has_exitsummary && - !memcmp(rs_out.descriptor_digest, + fast_memeq(rs_out.descriptor_digest, vsr->status.descriptor_digest, DIGEST_LEN)) { tor_assert(vsr->status.exitsummary); @@ -2204,7 +2205,8 @@ networkstatus_add_detached_signatures(networkstatus_t *target, } for (alg = DIGEST_SHA1; alg < N_DIGEST_ALGORITHMS; ++alg) { if (!tor_mem_is_zero(digests->d[alg], DIGEST256_LEN)) { - if (!memcmp(target->digests.d[alg], digests->d[alg], DIGEST256_LEN)) { + if (fast_memeq(target->digests.d[alg], digests->d[alg], + DIGEST256_LEN)) { ++n_matches; } else { *msg_out = "Mismatched digest."; @@ -2502,7 +2504,7 @@ authority_cert_dup(authority_cert_t *cert) void dirvote_get_preferred_voting_intervals(vote_timing_t *timing_out) { - or_options_t *options = get_options(); + const or_options_t *options = get_options(); tor_assert(timing_out); @@ -2576,7 +2578,7 @@ static struct { /** Set voting_schedule to hold the timing for the next vote we should be * doing. */ void -dirvote_recalculate_timing(or_options_t *options, time_t now) +dirvote_recalculate_timing(const or_options_t *options, time_t now) { int interval, vote_delay, dist_delay; time_t start; @@ -2627,7 +2629,7 @@ dirvote_recalculate_timing(or_options_t *options, time_t now) /** Entry point: Take whatever voting actions are pending as of <b>now</b>. */ void -dirvote_act(or_options_t *options, time_t now) +dirvote_act(const or_options_t *options, time_t now) { if (!authdir_mode_v3(options)) return; @@ -2968,11 +2970,11 @@ dirvote_add_vote(const char *vote_body, const char **msg_out, int *status_out) /* Now see whether we already have a vote from this authority. */ SMARTLIST_FOREACH(pending_vote_list, pending_vote_t *, v, { - if (! memcmp(v->vote->cert->cache_info.identity_digest, + if (fast_memeq(v->vote->cert->cache_info.identity_digest, vote->cert->cache_info.identity_digest, DIGEST_LEN)) { networkstatus_voter_info_t *vi_old = get_voter(v->vote); - if (!memcmp(vi_old->vote_digest, vi->vote_digest, DIGEST_LEN)) { + if (fast_memeq(vi_old->vote_digest, vi->vote_digest, DIGEST_LEN)) { /* Ah, it's the same vote. Not a problem. */ log_info(LD_DIR, "Discarding a vote we already have (from %s).", vi->address); @@ -3473,23 +3475,23 @@ dirvote_get_vote(const char *fp, int flags) if (by_id) { if (pending_vote_list && include_pending) { SMARTLIST_FOREACH(pending_vote_list, pending_vote_t *, pv, - if (!memcmp(get_voter(pv->vote)->identity_digest, fp, DIGEST_LEN)) + if (fast_memeq(get_voter(pv->vote)->identity_digest, fp, DIGEST_LEN)) return pv->vote_body); } if (previous_vote_list && include_previous) { SMARTLIST_FOREACH(previous_vote_list, pending_vote_t *, pv, - if (!memcmp(get_voter(pv->vote)->identity_digest, fp, DIGEST_LEN)) + if (fast_memeq(get_voter(pv->vote)->identity_digest, fp, DIGEST_LEN)) return pv->vote_body); } } else { if (pending_vote_list && include_pending) { SMARTLIST_FOREACH(pending_vote_list, pending_vote_t *, pv, - if (!memcmp(pv->vote->digests.d[DIGEST_SHA1], fp, DIGEST_LEN)) + if (fast_memeq(pv->vote->digests.d[DIGEST_SHA1], fp, DIGEST_LEN)) return pv->vote_body); } if (previous_vote_list && include_previous) { SMARTLIST_FOREACH(previous_vote_list, pending_vote_t *, pv, - if (!memcmp(pv->vote->digests.d[DIGEST_SHA1], fp, DIGEST_LEN)) + if (fast_memeq(pv->vote->digests.d[DIGEST_SHA1], fp, DIGEST_LEN)) return pv->vote_body); } } @@ -3608,7 +3610,7 @@ vote_routerstatus_find_microdesc_hash(char *digest256_out, * the first part. */ while (1) { num_len = strspn(cp, "1234567890"); - if (num_len == mlen && !memcmp(mstr, cp, mlen)) { + if (num_len == mlen && fast_memeq(mstr, cp, mlen)) { /* This is the line. */ char buf[BASE64_DIGEST256_LEN+1]; /* XXXX ignores extraneous stuff if the digest is too long. This diff --git a/src/or/dirvote.h b/src/or/dirvote.h index 97bed5ee6..b6746c655 100644 --- a/src/or/dirvote.h +++ b/src/or/dirvote.h @@ -41,8 +41,8 @@ authority_cert_t *authority_cert_dup(authority_cert_t *cert); /* vote scheduling */ void dirvote_get_preferred_voting_intervals(vote_timing_t *timing_out); time_t dirvote_get_start_of_next_interval(time_t now, int interval); -void dirvote_recalculate_timing(or_options_t *options, time_t now); -void dirvote_act(or_options_t *options, time_t now); +void dirvote_recalculate_timing(const or_options_t *options, time_t now); +void dirvote_act(const or_options_t *options, time_t now); /* invoked on timers and by outside triggers. */ struct pending_vote_t * dirvote_add_vote(const char *vote_body, diff --git a/src/or/dns.c b/src/or/dns.c index c8e101252..5d86e81fa 100644 --- a/src/or/dns.c +++ b/src/or/dns.c @@ -276,7 +276,7 @@ dns_init(void) int dns_reset(void) { - or_options_t *options = get_options(); + const or_options_t *options = get_options(); if (! server_mode(options)) { if (!the_evdns_base) { @@ -1026,7 +1026,7 @@ add_answer_to_cache(const char *address, uint8_t is_reverse, uint32_t addr, static INLINE int is_test_address(const char *address) { - or_options_t *options = get_options(); + const or_options_t *options = get_options(); return options->ServerDNSTestAddresses && smartlist_string_isin_case(options->ServerDNSTestAddresses, address); } @@ -1177,7 +1177,7 @@ evdns_err_is_transient(int err) static int configure_nameservers(int force) { - or_options_t *options; + const or_options_t *options; const char *conf_fname; struct stat st; int r; @@ -1295,14 +1295,17 @@ configure_nameservers(int force) nameservers_configured = 1; if (nameserver_config_failed) { nameserver_config_failed = 0; - mark_my_descriptor_dirty(); + /* XXX the three calls to republish the descriptor might be producing + * descriptors that are only cosmetically different, especially on + * non-exit relays! -RD */ + mark_my_descriptor_dirty("dns resolvers back"); } return 0; err: nameservers_configured = 0; if (! nameserver_config_failed) { nameserver_config_failed = 1; - mark_my_descriptor_dirty(); + mark_my_descriptor_dirty("dns resolvers failed"); } return -1; } @@ -1522,7 +1525,7 @@ add_wildcarded_test_address(const char *address) "broken.", address, n); if (!dns_is_completely_invalid) { dns_is_completely_invalid = 1; - mark_my_descriptor_dirty(); + mark_my_descriptor_dirty("dns hijacking confirmed"); } if (!dns_wildcarded_test_address_notice_given) control_event_server_status(LOG_WARN, "DNS_USELESS"); @@ -1592,7 +1595,7 @@ launch_wildcard_check(int min_len, int max_len, const char *suffix) static void launch_test_addresses(int fd, short event, void *args) { - or_options_t *options = get_options(); + const or_options_t *options = get_options(); struct evdns_request *req; (void)fd; (void)event; diff --git a/src/or/dnsserv.c b/src/or/dnsserv.c index 243b730cb..f2c473dfc 100644 --- a/src/or/dnsserv.c +++ b/src/or/dnsserv.c @@ -95,8 +95,8 @@ evdns_server_callback(struct evdns_server_request *req, void *_data) } if (!q) { log_info(LD_APP, "None of the questions we got were ones we're willing " - "to support. Sending NODATA."); - evdns_server_request_respond(req, DNS_ERR_NONE); + "to support. Sending NOTIMPL."); + evdns_server_request_respond(req, DNS_ERR_NOTIMPL); return; } if (q->type != EVDNS_TYPE_A) { @@ -306,7 +306,7 @@ void dnsserv_configure_listener(connection_t *conn) { tor_assert(conn); - tor_assert(conn->s >= 0); + tor_assert(SOCKET_OK(conn->s)); tor_assert(conn->type == CONN_TYPE_AP_DNS_LISTENER); conn->dns_server_port = diff --git a/src/or/eventdns.c b/src/or/eventdns.c index e9770c8c7..7fe376baf 100644 --- a/src/or/eventdns.c +++ b/src/or/eventdns.c @@ -461,7 +461,7 @@ sockaddr_eq(const struct sockaddr *sa1, const struct sockaddr *sa2, const struct sockaddr_in6 *sin1, *sin2; sin1 = (const struct sockaddr_in6 *)sa1; sin2 = (const struct sockaddr_in6 *)sa2; - if (memcmp(sin1->sin6_addr.s6_addr, sin2->sin6_addr.s6_addr, 16)) + if (tor_memneq(sin1->sin6_addr.s6_addr, sin2->sin6_addr.s6_addr, 16)) return 0; else if (include_port && sin1->sin6_port != sin2->sin6_port) return 0; @@ -1028,6 +1028,9 @@ request_parse(u8 *packet, ssize_t length, struct evdns_server_port *port, struct GET16(answers); GET16(authority); GET16(additional); + (void)additional; + (void)authority; + (void)answers; if (flags & 0x8000) return -1; /* Must not be an answer. */ flags &= 0x0110; /* Only RD and CD get preserved. */ @@ -1560,7 +1563,7 @@ evdns_request_data_build(const char *const name, const size_t name_len, /* exported function */ struct evdns_server_port * -evdns_add_server_port(int socket, int is_tcp, evdns_request_callback_fn_type cb, void *user_data) +evdns_add_server_port(tor_socket_t socket, int is_tcp, evdns_request_callback_fn_type cb, void *user_data) { struct evdns_server_port *port; if (!(port = mm_malloc(sizeof(struct evdns_server_port)))) @@ -1828,8 +1831,8 @@ evdns_server_request_respond(struct evdns_server_request *_req, int err) r = sendto(port->socket, req->response, req->response_len, 0, (struct sockaddr*) &req->addr, req->addrlen); if (r<0) { - int err = last_error(port->socket); - if (! error_is_eagain(err)) + int error = last_error(port->socket); + if (! error_is_eagain(error)) return -1; if (port->pending_replies) { @@ -2253,7 +2256,7 @@ sockaddr_is_loopback(const struct sockaddr *addr) return (ntohl(sin->sin_addr.s_addr) & 0xff000000) == 0x7f000000; } else if (addr->sa_family == AF_INET6) { struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr; - return !memcmp(sin6->sin6_addr.s6_addr, LOOPBACK_S6, 16); + return fast_memeq(sin6->sin6_addr.s6_addr, LOOPBACK_S6, 16); } return 0; } @@ -2288,7 +2291,7 @@ _evdns_nameserver_add_impl(const struct sockaddr *address, evtimer_set(&ns->timeout_event, nameserver_prod_callback, ns); - ns->socket = tor_open_socket(PF_INET, SOCK_DGRAM, 0); + ns->socket = tor_open_socket(address->sa_family, SOCK_DGRAM, 0); if (ns->socket < 0) { err = 1; goto out1; } #ifdef WIN32 { diff --git a/src/or/eventdns.h b/src/or/eventdns.h index 2fe4ac937..3ff8bba4b 100644 --- a/src/or/eventdns.h +++ b/src/or/eventdns.h @@ -319,7 +319,7 @@ typedef void (*evdns_request_callback_fn_type)(struct evdns_server_request *, vo #define EVDNS_CLASS_INET 1 -struct evdns_server_port *evdns_add_server_port(int socket, int is_tcp, evdns_request_callback_fn_type callback, void *user_data); +struct evdns_server_port *evdns_add_server_port(tor_socket_t socket, int is_tcp, evdns_request_callback_fn_type callback, void *user_data); void evdns_close_server_port(struct evdns_server_port *port); int evdns_server_request_add_reply(struct evdns_server_request *req, int section, const char *name, int type, int class, int ttl, int datalen, int is_name, const char *data); diff --git a/src/or/geoip.c b/src/or/geoip.c index 71ed3bedf..62c7a5c39 100644 --- a/src/or/geoip.c +++ b/src/or/geoip.c @@ -116,10 +116,10 @@ geoip_parse_entry(const char *line) ++line; if (*line == '#') return 0; - if (sscanf(line,"%u,%u,%2s", &low, &high, b) == 3) { + if (tor_sscanf(line,"%u,%u,%2s", &low, &high, b) == 3) { geoip_add_entry(low, high, b); return 0; - } else if (sscanf(line,"\"%u\",\"%u\",\"%2s\",", &low, &high, b) == 3) { + } else if (tor_sscanf(line,"\"%u\",\"%u\",\"%2s\",", &low, &high, b) == 3) { geoip_add_entry(low, high, b); return 0; } else { @@ -162,7 +162,7 @@ _geoip_compare_key_to_entry(const void *_key, const void **_member) /** Return 1 if we should collect geoip stats on bridge users, and * include them in our extrainfo descriptor. Else return 0. */ int -should_record_bridge_info(or_options_t *options) +should_record_bridge_info(const or_options_t *options) { return options->BridgeRelay && options->BridgeRecordUsageByCountry; } @@ -199,7 +199,7 @@ init_geoip_countries(void) * with '#' (comments). */ int -geoip_load_file(const char *filename, or_options_t *options) +geoip_load_file(const char *filename, const or_options_t *options) { FILE *f; const char *msg = ""; @@ -424,7 +424,7 @@ void geoip_note_client_seen(geoip_client_action_t action, uint32_t addr, time_t now) { - or_options_t *options = get_options(); + const or_options_t *options = get_options(); clientmap_entry_t lookup, *ent; if (action == GEOIP_CLIENT_CONNECT) { /* Only remember statistics as entry guard or as bridge. */ @@ -990,7 +990,7 @@ geoip_dirreq_stats_write(time_t now) geoip_remove_old_clients(start_of_dirreq_stats_interval); statsdir = get_datadir_fname("stats"); - if (check_private_dir(statsdir, CPD_CREATE) < 0) + if (check_private_dir(statsdir, CPD_CREATE, get_options()->User) < 0) goto done; filename = get_datadir_fname2("stats", "dirreq-stats"); data_v2 = geoip_get_client_history(GEOIP_CLIENT_NETWORKSTATUS_V2); @@ -1229,7 +1229,7 @@ geoip_bridge_stats_write(time_t now) /* Write it to disk. */ statsdir = get_datadir_fname("stats"); - if (check_private_dir(statsdir, CPD_CREATE) < 0) + if (check_private_dir(statsdir, CPD_CREATE, get_options()->User) < 0) goto done; filename = get_datadir_fname2("stats", "bridge-stats"); @@ -1324,7 +1324,7 @@ geoip_entry_stats_write(time_t now) geoip_remove_old_clients(start_of_entry_stats_interval); statsdir = get_datadir_fname("stats"); - if (check_private_dir(statsdir, CPD_CREATE) < 0) + if (check_private_dir(statsdir, CPD_CREATE, get_options()->User) < 0) goto done; filename = get_datadir_fname2("stats", "entry-stats"); data = geoip_get_client_history(GEOIP_CLIENT_CONNECT); diff --git a/src/or/geoip.h b/src/or/geoip.h index 02228eab3..b50da74dc 100644 --- a/src/or/geoip.h +++ b/src/or/geoip.h @@ -15,8 +15,8 @@ #ifdef GEOIP_PRIVATE int geoip_parse_entry(const char *line); #endif -int should_record_bridge_info(or_options_t *options); -int geoip_load_file(const char *filename, or_options_t *options); +int should_record_bridge_info(const or_options_t *options); +int geoip_load_file(const char *filename, const or_options_t *options); int geoip_get_country_by_ip(uint32_t ipaddr); int geoip_get_n_countries(void); const char *geoip_get_country_name(country_t num); diff --git a/src/or/hibernate.c b/src/or/hibernate.c index aebce4cc8..f03433a27 100644 --- a/src/or/hibernate.c +++ b/src/or/hibernate.c @@ -134,7 +134,7 @@ static void accounting_set_wakeup_time(void); * options->AccountingStart. Return 0 on success, -1 on failure. If * <b>validate_only</b> is true, do not change the current settings. */ int -accounting_parse_options(or_options_t *options, int validate_only) +accounting_parse_options(const or_options_t *options, int validate_only) { time_unit_t unit; int ok, idx; @@ -249,7 +249,7 @@ accounting_parse_options(or_options_t *options, int validate_only) * hibernate, return 1, else return 0. */ int -accounting_is_enabled(or_options_t *options) +accounting_is_enabled(const or_options_t *options) { if (options->AccountingMax) return 1; @@ -411,7 +411,7 @@ static void update_expected_bandwidth(void) { uint64_t expected; - or_options_t *options= get_options(); + const or_options_t *options= get_options(); uint64_t max_configured = (options->RelayBandwidthRate > 0 ? options->RelayBandwidthRate : options->BandwidthRate) * 60; @@ -750,7 +750,7 @@ static void hibernate_begin(hibernate_state_t new_state, time_t now) { connection_t *conn; - or_options_t *options = get_options(); + const or_options_t *options = get_options(); if (new_state == HIBERNATE_STATE_EXITING && hibernate_state != HIBERNATE_STATE_LIVE) { diff --git a/src/or/hibernate.h b/src/or/hibernate.h index 2aea0fab0..b5826bced 100644 --- a/src/or/hibernate.h +++ b/src/or/hibernate.h @@ -12,8 +12,8 @@ #ifndef _TOR_HIBERNATE_H #define _TOR_HIBERNATE_H -int accounting_parse_options(or_options_t *options, int validate_only); -int accounting_is_enabled(or_options_t *options); +int accounting_parse_options(const or_options_t *options, int validate_only); +int accounting_is_enabled(const or_options_t *options); void configure_accounting(time_t now); void accounting_run_housekeeping(time_t now); void accounting_add_bytes(size_t n_read, size_t n_written, int seconds); diff --git a/src/or/main.c b/src/or/main.c index 0e866b730..9536ae449 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -68,8 +68,8 @@ void evdns_shutdown(int); static void dumpmemusage(int severity); static void dumpstats(int severity); /* log stats */ -static void conn_read_callback(int fd, short event, void *_conn); -static void conn_write_callback(int fd, short event, void *_conn); +static void conn_read_callback(evutil_socket_t fd, short event, void *_conn); +static void conn_write_callback(evutil_socket_t fd, short event, void *_conn); static void second_elapsed_callback(periodic_timer_t *timer, void *args); static int conn_close_if_marked(int i); static void connection_start_reading_from_linked_conn(connection_t *conn); @@ -195,7 +195,7 @@ int connection_add_impl(connection_t *conn, int is_connecting) { tor_assert(conn); - tor_assert(conn->s >= 0 || + tor_assert(SOCKET_OK(conn->s) || conn->linked || (conn->type == CONN_TYPE_AP && TO_EDGE_CONN(conn)->is_dns_request)); @@ -206,7 +206,7 @@ connection_add_impl(connection_t *conn, int is_connecting) #ifdef USE_BUFFEREVENTS if (connection_type_uses_bufferevent(conn)) { - if (conn->s >= 0 && !conn->linked) { + if (SOCKET_OK(conn->s) && !conn->linked) { conn->bufev = bufferevent_socket_new( tor_libevent_get_base(), conn->s, @@ -225,7 +225,7 @@ connection_add_impl(connection_t *conn, int is_connecting) connection_configure_bufferevent_callbacks(conn); } else if (conn->linked && conn->linked_conn && connection_type_uses_bufferevent(conn->linked_conn)) { - tor_assert(conn->s < 0); + tor_assert(!(SOCKET_OK(conn->s))); if (!conn->bufev) { struct bufferevent *pair[2] = { NULL, NULL }; if (bufferevent_pair_new(tor_libevent_get_base(), @@ -255,7 +255,7 @@ connection_add_impl(connection_t *conn, int is_connecting) (void) is_connecting; #endif - if (!HAS_BUFFEREVENT(conn) && (conn->s >= 0 || conn->linked)) { + if (!HAS_BUFFEREVENT(conn) && (SOCKET_OK(conn->s) || conn->linked)) { conn->read_event = tor_event_new(tor_libevent_get_base(), conn->s, EV_READ|EV_PERSIST, conn_read_callback, conn); conn->write_event = tor_event_new(tor_libevent_get_base(), @@ -264,7 +264,7 @@ connection_add_impl(connection_t *conn, int is_connecting) } log_debug(LD_NET,"new conn type %s, socket %d, address %s, n_conns %d.", - conn_type_to_string(conn->type), conn->s, conn->address, + conn_type_to_string(conn->type), (int)conn->s, conn->address, smartlist_len(connection_array)); return 0; @@ -276,12 +276,12 @@ connection_unregister_events(connection_t *conn) { if (conn->read_event) { if (event_del(conn->read_event)) - log_warn(LD_BUG, "Error removing read event for %d", conn->s); + log_warn(LD_BUG, "Error removing read event for %d", (int)conn->s); tor_free(conn->read_event); } if (conn->write_event) { if (event_del(conn->write_event)) - log_warn(LD_BUG, "Error removing write event for %d", conn->s); + log_warn(LD_BUG, "Error removing write event for %d", (int)conn->s); tor_free(conn->write_event); } #ifdef USE_BUFFEREVENTS @@ -308,7 +308,7 @@ connection_remove(connection_t *conn) tor_assert(conn); log_debug(LD_NET,"removing socket %d (type %s), n_conns now %d", - conn->s, conn_type_to_string(conn->type), + (int)conn->s, conn_type_to_string(conn->type), smartlist_len(connection_array)); tor_assert(conn->conn_array_index >= 0); @@ -473,7 +473,7 @@ connection_stop_reading(connection_t *conn) if (event_del(conn->read_event)) log_warn(LD_NET, "Error from libevent setting read event state for %d " "to unwatched: %s", - conn->s, + (int)conn->s, tor_socket_strerror(tor_socket_errno(conn->s))); } } @@ -499,7 +499,7 @@ connection_start_reading(connection_t *conn) if (event_add(conn->read_event, NULL)) log_warn(LD_NET, "Error from libevent setting read event state for %d " "to watched: %s", - conn->s, + (int)conn->s, tor_socket_strerror(tor_socket_errno(conn->s))); } } @@ -539,7 +539,7 @@ connection_stop_writing(connection_t *conn) if (event_del(conn->write_event)) log_warn(LD_NET, "Error from libevent setting write event state for %d " "to unwatched: %s", - conn->s, + (int)conn->s, tor_socket_strerror(tor_socket_errno(conn->s))); } } @@ -566,7 +566,7 @@ connection_start_writing(connection_t *conn) if (event_add(conn->write_event, NULL)) log_warn(LD_NET, "Error from libevent setting write event state for %d " "to watched: %s", - conn->s, + (int)conn->s, tor_socket_strerror(tor_socket_errno(conn->s))); } } @@ -652,13 +652,13 @@ close_closeable_connections(void) /** Libevent callback: this gets invoked when (connection_t*)<b>conn</b> has * some data to read. */ static void -conn_read_callback(int fd, short event, void *_conn) +conn_read_callback(evutil_socket_t fd, short event, void *_conn) { connection_t *conn = _conn; (void)fd; (void)event; - log_debug(LD_NET,"socket %d wants to read.",conn->s); + log_debug(LD_NET,"socket %d wants to read.",(int)conn->s); /* assert_connection_ok(conn, time(NULL)); */ @@ -667,7 +667,7 @@ conn_read_callback(int fd, short event, void *_conn) #ifndef MS_WINDOWS log_warn(LD_BUG,"Unhandled error on read for %s connection " "(fd %d); removing", - conn_type_to_string(conn->type), conn->s); + conn_type_to_string(conn->type), (int)conn->s); tor_fragile_assert(); #endif if (CONN_IS_EDGE(conn)) @@ -684,13 +684,14 @@ conn_read_callback(int fd, short event, void *_conn) /** Libevent callback: this gets invoked when (connection_t*)<b>conn</b> has * some data to write. */ static void -conn_write_callback(int fd, short events, void *_conn) +conn_write_callback(evutil_socket_t fd, short events, void *_conn) { connection_t *conn = _conn; (void)fd; (void)events; - LOG_FN_CONN(conn, (LOG_DEBUG, LD_NET, "socket %d wants to write.",conn->s)); + LOG_FN_CONN(conn, (LOG_DEBUG, LD_NET, "socket %d wants to write.", + (int)conn->s)); /* assert_connection_ok(conn, time(NULL)); */ @@ -699,7 +700,7 @@ conn_write_callback(int fd, short events, void *_conn) /* this connection is broken. remove it. */ log_fn(LOG_WARN,LD_BUG, "unhandled error on write for %s connection (fd %d); removing", - conn_type_to_string(conn->type), conn->s); + conn_type_to_string(conn->type), (int)conn->s); tor_fragile_assert(); if (CONN_IS_EDGE(conn)) { /* otherwise we cry wolf about duplicate close */ @@ -757,7 +758,8 @@ conn_close_if_marked(int i) log_debug(LD_NET,"Cleaning up connection (fd %d).",conn->s); IF_HAS_BUFFEREVENT(conn, goto unlink); - if ((conn->s >= 0 || conn->linked_conn) && connection_wants_to_flush(conn)) { + if ((SOCKET_OK(conn->s) || conn->linked_conn) && + connection_wants_to_flush(conn)) { /* s == -1 means it's an incomplete edge connection, or that the socket * has already been closed as unflushable. */ ssize_t sz = connection_bucket_write_limit(conn, now); @@ -766,7 +768,7 @@ conn_close_if_marked(int i) "Conn (addr %s, fd %d, type %s, state %d) marked, but wants " "to flush %d bytes. (Marked at %s:%d)", escaped_safe_str_client(conn->address), - conn->s, conn_type_to_string(conn->type), conn->state, + (int)conn->s, conn_type_to_string(conn->type), conn->state, (int)conn->outbuf_flushlen, conn->marked_for_close_file, conn->marked_for_close); if (conn->linked_conn) { @@ -797,7 +799,7 @@ conn_close_if_marked(int i) if (retval > 0) { LOG_FN_CONN(conn, (LOG_INFO,LD_NET, "Holding conn (fd %d) open for more flushing.", - conn->s)); + (int)conn->s)); conn->timestamp_lastwritten = now; /* reset so we can flush more */ } return 0; @@ -819,7 +821,7 @@ conn_close_if_marked(int i) "(fd %d, type %s, state %d, marked at %s:%d).", (int)connection_get_outbuf_len(conn), escaped_safe_str_client(conn->address), - conn->s, conn_type_to_string(conn->type), conn->state, + (int)conn->s, conn_type_to_string(conn->type), conn->state, conn->marked_for_close_file, conn->marked_for_close); } @@ -865,7 +867,7 @@ directory_all_unreachable(time_t now) void directory_info_has_arrived(time_t now, int from_cache) { - or_options_t *options = get_options(); + const or_options_t *options = get_options(); if (!router_have_minimum_dir_info()) { int quiet = directory_too_idle_to_fetch_descriptors(options, now); @@ -910,7 +912,7 @@ run_connection_housekeeping(int i, time_t now) { cell_t cell; connection_t *conn = smartlist_get(connection_array, i); - or_options_t *options = get_options(); + const or_options_t *options = get_options(); or_connection_t *or_conn; int past_keepalive = now >= conn->timestamp_lastwritten + options->KeepalivePeriod; @@ -932,7 +934,7 @@ run_connection_housekeeping(int i, time_t now) (!DIR_CONN_IS_SERVER(conn) && conn->timestamp_lastread + DIR_CONN_MAX_STALL < now))) { log_info(LD_DIR,"Expiring wedged directory conn (fd %d, purpose %d)", - conn->s, conn->purpose); + (int)conn->s, conn->purpose); /* This check is temporary; it's to let us know whether we should consider * parsing partial serverdesc responses. */ if (conn->purpose == DIR_PURPOSE_FETCH_SERVERDESC && @@ -964,7 +966,7 @@ run_connection_housekeeping(int i, time_t now) * mark it now. */ log_info(LD_OR, "Expiring non-used OR connection to fd %d (%s:%d) [Too old].", - conn->s, conn->address, conn->port); + (int)conn->s, conn->address, conn->port); if (conn->state == OR_CONN_STATE_CONNECTING) connection_or_connect_failed(TO_OR_CONN(conn), END_OR_CONN_REASON_TIMEOUT, @@ -974,7 +976,7 @@ run_connection_housekeeping(int i, time_t now) if (past_keepalive) { /* We never managed to actually get this connection open and happy. */ log_info(LD_OR,"Expiring non-open OR connection to fd %d (%s:%d).", - conn->s,conn->address, conn->port); + (int)conn->s,conn->address, conn->port); connection_mark_for_close(conn); } } else if (we_are_hibernating() && !or_conn->n_circuits && @@ -982,13 +984,13 @@ run_connection_housekeeping(int i, time_t now) /* We're hibernating, there's no circuits, and nothing to flush.*/ log_info(LD_OR,"Expiring non-used OR connection to fd %d (%s:%d) " "[Hibernating or exiting].", - conn->s,conn->address, conn->port); + (int)conn->s,conn->address, conn->port); connection_mark_and_flush(conn); } else if (!or_conn->n_circuits && now >= or_conn->timestamp_last_added_nonpadding + IDLE_OR_CONN_TIMEOUT) { log_info(LD_OR,"Expiring non-used OR connection to fd %d (%s:%d) " - "[idle %d].", conn->s,conn->address, conn->port, + "[idle %d].", (int)conn->s,conn->address, conn->port, (int)(now - or_conn->timestamp_last_added_nonpadding)); connection_mark_for_close(conn); } else if ( @@ -997,7 +999,7 @@ run_connection_housekeeping(int i, time_t now) log_fn(LOG_PROTOCOL_WARN,LD_PROTOCOL, "Expiring stuck OR connection to fd %d (%s:%d). (%d bytes to " "flush; %d seconds since last write)", - conn->s, conn->address, conn->port, + (int)conn->s, conn->address, conn->port, (int)connection_get_outbuf_len(conn), (int)(now-conn->timestamp_lastwritten)); connection_mark_for_close(conn); @@ -1016,7 +1018,7 @@ run_connection_housekeeping(int i, time_t now) static void signewnym_impl(time_t now) { - or_options_t *options = get_options(); + const or_options_t *options = get_options(); if (!proxy_mode(options)) { log_info(LD_CONTROL, "Ignoring SIGNAL NEWNYM because client functionality " "is disabled."); @@ -1025,10 +1027,11 @@ signewnym_impl(time_t now) circuit_expire_all_dirty_circs(); addressmap_clear_transient(); - rend_cache_purge(); - rend_client_cancel_descriptor_fetches(); + rend_client_purge_state(); time_of_last_signewnym = now; signewnym_is_pending = 0; + + control_event_signal(SIGNEWNYM); } /** Perform regular maintenance tasks. This function gets run once per @@ -1059,7 +1062,7 @@ run_scheduled_events(time_t now) static int should_init_bridge_stats = 1; static time_t time_to_retry_dns_init = 0; static time_t time_to_next_heartbeat = 0; - or_options_t *options = get_options(); + const or_options_t *options = get_options(); int is_server = server_mode(options); int i; int have_dir_info; @@ -1110,8 +1113,6 @@ run_scheduled_events(time_t now) if (time_to_try_getting_descriptors < now) { update_all_descriptor_downloads(now); update_extrainfo_downloads(now); - if (options->UseBridges) - fetch_bridge_descriptors(options, now); if (router_have_minimum_dir_info()) time_to_try_getting_descriptors = now + LAZY_DESCRIPTOR_RETRY_INTERVAL; else @@ -1124,6 +1125,9 @@ run_scheduled_events(time_t now) now + DESCRIPTOR_FAILURE_RESET_INTERVAL; } + if (options->UseBridges) + fetch_bridge_descriptors(options, now); + /** 1b. Every MAX_SSL_KEY_LIFETIME seconds, we change our TLS context. */ if (!last_rotated_x509_certificate) last_rotated_x509_certificate = now; @@ -1351,7 +1355,10 @@ run_scheduled_events(time_t now) * it's not comfortable with the number of available circuits. */ /* XXXX022 If our circuit build timeout is much lower than a second, maybe - we should do this more often? */ + * we should do this more often? -NM + * It can't be lower than 1.5 seconds currently; see + * circuit_build_times_min_timeout(). -RD + */ circuit_expire_building(); /** 3b. Also look at pending streams and prune the ones that 'began' @@ -1482,7 +1489,7 @@ second_elapsed_callback(periodic_timer_t *timer, void *arg) #ifdef USE_BUFFEREVENTS uint64_t cur_read,cur_written; #endif - or_options_t *options = get_options(); + const or_options_t *options = get_options(); (void)timer; (void)arg; @@ -1602,7 +1609,7 @@ ip_address_changed(int at_interface) reset_bandwidth_test(); stats_n_seconds_working = 0; router_reset_reachability(); - mark_my_descriptor_dirty(); + mark_my_descriptor_dirty("IP address changed"); } } @@ -1625,7 +1632,7 @@ dns_servers_relaunch_checks(void) static int do_hup(void) { - or_options_t *options = get_options(); + const or_options_t *options = get_options(); #ifdef USE_DMALLOC dmalloc_log_stats(); @@ -1639,7 +1646,6 @@ do_hup(void) router_reset_warnings(); routerlist_reset_warnings(); - addressmap_clear_transient(); /* first, reload config variables, in case they've changed */ if (options->ReloadTorrcOnSIGHUP) { /* no need to provide argc/v, they've been cached in init_from_config */ @@ -1883,7 +1889,6 @@ process_signal(uintptr_t sig) (int)(MAX_SIGNEWNYM_RATE+time_of_last_signewnym-now)); } else { signewnym_impl(now); - control_event_signal(sig); } break; } @@ -1936,7 +1941,7 @@ dumpstats(int severity) int i = conn_sl_idx; log(severity, LD_GENERAL, "Conn %d (socket %d) type %d (%s), state %d (%s), created %d secs ago", - i, conn->s, conn->type, conn_type_to_string(conn->type), + i, (int)conn->s, conn->type, conn_type_to_string(conn->type), conn->state, conn_state_to_string(conn->type, conn->state), (int)(now - conn->timestamp_created)); if (!connection_is_listener(conn)) { @@ -2168,7 +2173,7 @@ static tor_lockfile_t *lockfile = NULL; * return -1 if we can't get the lockfile. Return 0 on success. */ int -try_locking(or_options_t *options, int err_if_locked) +try_locking(const or_options_t *options, int err_if_locked) { if (lockfile) return 0; @@ -2282,13 +2287,15 @@ tor_free_all(int postfork) void tor_cleanup(void) { - or_options_t *options = get_options(); - /* Remove our pid file. We don't care if there was an error when we - * unlink, nothing we could do about it anyways. */ + const or_options_t *options = get_options(); if (options->command == CMD_RUN_TOR) { time_t now = time(NULL); + /* Remove our pid file. We don't care if there was an error when we + * unlink, nothing we could do about it anyways. */ if (options->PidFile) unlink(options->PidFile); + if (options->ControlPortWriteToFile) + unlink(options->ControlPortWriteToFile); if (accounting_is_enabled(options)) accounting_record_bandwidth_usage(now, get_or_state()); or_state_mark_dirty(get_or_state(), 0); /* force an immediate save. */ diff --git a/src/or/main.h b/src/or/main.h index db97cf1c4..db251356f 100644 --- a/src/or/main.h +++ b/src/or/main.h @@ -56,7 +56,7 @@ long get_uptime(void); void handle_signals(int is_parent); void process_signal(uintptr_t sig); -int try_locking(or_options_t *options, int err_if_locked); +int try_locking(const or_options_t *options, int err_if_locked); int have_lockfile(void); void release_lockfile(void); diff --git a/src/or/microdesc.c b/src/or/microdesc.c index ba4532ef6..1b0c333da 100644 --- a/src/or/microdesc.c +++ b/src/or/microdesc.c @@ -55,7 +55,7 @@ _microdesc_hash(microdesc_t *md) static INLINE int _microdesc_eq(microdesc_t *a, microdesc_t *b) { - return !memcmp(a->digest, b->digest, DIGEST256_LEN); + return tor_memeq(a->digest, b->digest, DIGEST256_LEN); } HT_PROTOTYPE(microdesc_map, microdesc_t, node, @@ -452,10 +452,11 @@ microdesc_cache_rebuild(microdesc_cache_t *cache, int force) smartlist_add(wrote, md); } - finish_writing_to_file(open_file); /*XXX Check me.*/ - if (cache->cache_content) tor_munmap_file(cache->cache_content); + + finish_writing_to_file(open_file); /*XXX Check me.*/ + cache->cache_content = tor_mmap_file(cache->cache_fname); if (!cache->cache_content && smartlist_len(wrote)) { @@ -468,7 +469,7 @@ microdesc_cache_rebuild(microdesc_cache_t *cache, int force) tor_assert(md->saved_location == SAVED_IN_CACHE); md->body = (char*)cache->cache_content->data + md->off; if (PREDICT_UNLIKELY( - md->bodylen < 9 || memcmp(md->body, "onion-key", 9) != 0)) { + md->bodylen < 9 || fast_memneq(md->body, "onion-key", 9) != 0)) { /* XXXX023 once bug 2022 is solved, we can kill this block and turn it * into just the tor_assert(!memcmp) */ off_t avail = cache->cache_content->size - md->off; @@ -480,7 +481,7 @@ microdesc_cache_rebuild(microdesc_cache_t *cache, int force) " with \"onion-key\". Instead I got %s.", (int)md->off, escaped(bad_str)); tor_free(bad_str); - tor_assert(!memcmp(md->body, "onion-key", 9)); + tor_assert(fast_memeq(md->body, "onion-key", 9)); } } SMARTLIST_FOREACH_END(md); @@ -633,7 +634,7 @@ microdesc_list_missing_digest256(networkstatus_t *ns, microdesc_cache_t *cache, void update_microdesc_downloads(time_t now) { - or_options_t *options = get_options(); + const or_options_t *options = get_options(); networkstatus_t *consensus; smartlist_t *missing; digestmap_t *pending; @@ -692,7 +693,7 @@ update_microdescs_from_networkstatus(time_t now) /** Return true iff we should prefer to use microdescriptors rather than * routerdescs for building circuits. */ int -we_use_microdescriptors_for_circuits(or_options_t *options) +we_use_microdescriptors_for_circuits(const or_options_t *options) { int ret = options->UseMicrodescriptors; if (ret == -1) { @@ -711,7 +712,7 @@ we_use_microdescriptors_for_circuits(or_options_t *options) /** Return true iff we should try to download microdescriptors at all. */ int -we_fetch_microdescriptors(or_options_t *options) +we_fetch_microdescriptors(const or_options_t *options) { if (directory_caches_dir_info(options)) return 1; @@ -720,7 +721,7 @@ we_fetch_microdescriptors(or_options_t *options) /** Return true iff we should try to download router descriptors at all. */ int -we_fetch_router_descriptors(or_options_t *options) +we_fetch_router_descriptors(const or_options_t *options) { if (directory_caches_dir_info(options)) return 1; diff --git a/src/or/microdesc.h b/src/or/microdesc.h index 94b1ff6f8..72e4572f9 100644 --- a/src/or/microdesc.h +++ b/src/or/microdesc.h @@ -44,9 +44,9 @@ void update_microdesc_downloads(time_t now); void update_microdescs_from_networkstatus(time_t now); int usable_consensus_flavor(void); -int we_fetch_microdescriptors(or_options_t *options); -int we_fetch_router_descriptors(or_options_t *options); -int we_use_microdescriptors_for_circuits(or_options_t *options); +int we_fetch_microdescriptors(const or_options_t *options); +int we_fetch_router_descriptors(const or_options_t *options); +int we_use_microdescriptors_for_circuits(const or_options_t *options); #endif diff --git a/src/or/networkstatus.c b/src/or/networkstatus.c index 7fd3d365f..2586ce6eb 100644 --- a/src/or/networkstatus.c +++ b/src/or/networkstatus.c @@ -213,7 +213,7 @@ router_reload_consensus_networkstatus(void) char *filename; char *s; struct stat st; - or_options_t *options = get_options(); + const or_options_t *options = get_options(); const unsigned int flags = NSSET_FROM_CACHE | NSSET_DONT_DOWNLOAD_CERTS; int flav; @@ -424,7 +424,7 @@ networkstatus_get_voter_by_id(networkstatus_t *vote, if (!vote || !vote->voters) return NULL; SMARTLIST_FOREACH(vote->voters, networkstatus_voter_info_t *, voter, - if (!memcmp(voter->identity_digest, identity, DIGEST_LEN)) + if (fast_memeq(voter->identity_digest, identity, DIGEST_LEN)) return voter); return NULL; } @@ -445,9 +445,9 @@ networkstatus_check_document_signature(const networkstatus_t *consensus, if (crypto_pk_get_digest(cert->signing_key, key_digest)<0) return -1; - if (memcmp(sig->signing_key_digest, key_digest, DIGEST_LEN) || - memcmp(sig->identity_digest, cert->cache_info.identity_digest, - DIGEST_LEN)) + if (tor_memneq(sig->signing_key_digest, key_digest, DIGEST_LEN) || + tor_memneq(sig->identity_digest, cert->cache_info.identity_digest, + DIGEST_LEN)) return -1; signed_digest_len = crypto_pk_keysize(cert->signing_key); @@ -457,7 +457,7 @@ networkstatus_check_document_signature(const networkstatus_t *consensus, signed_digest_len, sig->signature, sig->signature_len) < dlen || - memcmp(signed_digest, consensus->digests.d[sig->alg], dlen)) { + tor_memneq(signed_digest, consensus->digests.d[sig->alg], dlen)) { log_warn(LD_DIR, "Got a bad signature on a networkstatus vote"); sig->bad_signature = 1; } else { @@ -509,7 +509,7 @@ networkstatus_check_consensus_signature(networkstatus_t *consensus, authority_cert_t *cert = authority_cert_get_by_digests(sig->identity_digest, sig->signing_key_digest); - tor_assert(!memcmp(sig->identity_digest, voter->identity_digest, + tor_assert(tor_memeq(sig->identity_digest, voter->identity_digest, DIGEST_LEN)); if (!is_v3_auth) { @@ -812,8 +812,8 @@ router_set_networkstatus_v2(const char *s, time_t arrived_at, for (i=0; i < smartlist_len(networkstatus_v2_list); ++i) { networkstatus_v2_t *old_ns = smartlist_get(networkstatus_v2_list, i); - if (!memcmp(old_ns->identity_digest, ns->identity_digest, DIGEST_LEN)) { - if (!memcmp(old_ns->networkstatus_digest, + if (tor_memeq(old_ns->identity_digest, ns->identity_digest, DIGEST_LEN)) { + if (tor_memeq(old_ns->networkstatus_digest, ns->networkstatus_digest, DIGEST_LEN)) { /* Same one we had before. */ networkstatus_v2_free(ns); @@ -939,7 +939,7 @@ compare_digest_to_routerstatus_entry(const void *_key, const void **_member) { const char *key = _key; const routerstatus_t *rs = *_member; - return memcmp(key, rs->identity_digest, DIGEST_LEN); + return tor_memcmp(key, rs->identity_digest, DIGEST_LEN); } /** As networkstatus_v2_find_entry, but do not return a const pointer */ @@ -1175,7 +1175,7 @@ update_v2_networkstatus_cache_downloads(time_t now) /** DOCDOC */ static int -we_want_to_fetch_flavor(or_options_t *options, int flavor) +we_want_to_fetch_flavor(const or_options_t *options, int flavor) { if (flavor < 0 || flavor > N_CONSENSUS_FLAVORS) { /* This flavor is crazy; we don't want it */ @@ -1204,7 +1204,7 @@ static void update_consensus_networkstatus_downloads(time_t now) { int i; - or_options_t *options = get_options(); + const or_options_t *options = get_options(); if (!networkstatus_get_live_consensus(now)) time_to_download_next_consensus = now; /* No live consensus? Get one now!*/ @@ -1274,7 +1274,7 @@ networkstatus_consensus_download_failed(int status_code, const char *flavname) void update_consensus_networkstatus_fetch_time(time_t now) { - or_options_t *options = get_options(); + const or_options_t *options = get_options(); networkstatus_t *c = networkstatus_get_live_consensus(now); if (c) { long dl_interval; @@ -1348,7 +1348,7 @@ update_consensus_networkstatus_fetch_time(time_t now) * fetches yet (e.g. we demand bridges and none are yet known). * Else return 0. */ int -should_delay_dir_fetches(or_options_t *options) +should_delay_dir_fetches(const or_options_t *options) { if (options->UseBridges && !any_bridge_descriptors_known()) { log_info(LD_DIR, "delaying dir fetches (no running bridges known)"); @@ -1362,7 +1362,7 @@ should_delay_dir_fetches(or_options_t *options) void update_networkstatus_downloads(time_t now) { - or_options_t *options = get_options(); + const or_options_t *options = get_options(); if (should_delay_dir_fetches(options)) return; if (authdir_mode_any_main(options) || options->FetchV2Networkstatus) @@ -1404,7 +1404,7 @@ networkstatus_v2_get_by_digest(const char *digest) { SMARTLIST_FOREACH(networkstatus_v2_list, networkstatus_v2_t *, ns, { - if (!memcmp(ns->identity_digest, digest, DIGEST_LEN)) + if (tor_memeq(ns->identity_digest, digest, DIGEST_LEN)) return ns; }); return NULL; @@ -1467,10 +1467,10 @@ networkstatus_get_reasonably_live_consensus(time_t now, int flavor) static int routerstatus_has_changed(const routerstatus_t *a, const routerstatus_t *b) { - tor_assert(!memcmp(a->identity_digest, b->identity_digest, DIGEST_LEN)); + tor_assert(tor_memeq(a->identity_digest, b->identity_digest, DIGEST_LEN)); return strcmp(a->nickname, b->nickname) || - memcmp(a->descriptor_digest, b->descriptor_digest, DIGEST_LEN) || + fast_memneq(a->descriptor_digest, b->descriptor_digest, DIGEST_LEN) || a->addr != b->addr || a->or_port != b->or_port || a->dir_port != b->dir_port || @@ -1522,7 +1522,7 @@ notify_control_networkstatus_changed(const networkstatus_t *old_c, SMARTLIST_FOREACH_JOIN( old_c->routerstatus_list, const routerstatus_t *, rs_old, new_c->routerstatus_list, const routerstatus_t *, rs_new, - memcmp(rs_old->identity_digest, + tor_memcmp(rs_old->identity_digest, rs_new->identity_digest, DIGEST_LEN), smartlist_add(changed, (void*) rs_new)) { if (routerstatus_has_changed(rs_old, rs_new)) @@ -1546,13 +1546,13 @@ networkstatus_copy_old_consensus_info(networkstatus_t *new_c, SMARTLIST_FOREACH_JOIN(old_c->routerstatus_list, routerstatus_t *, rs_old, new_c->routerstatus_list, routerstatus_t *, rs_new, - memcmp(rs_old->identity_digest, + tor_memcmp(rs_old->identity_digest, rs_new->identity_digest, DIGEST_LEN), STMT_NIL) { /* Okay, so we're looking at the same identity. */ rs_new->last_dir_503_at = rs_old->last_dir_503_at; - if (!memcmp(rs_old->descriptor_digest, rs_new->descriptor_digest, + if (tor_memeq(rs_old->descriptor_digest, rs_new->descriptor_digest, DIGEST_LEN)) { /* And the same descriptor too! */ memcpy(&rs_new->dl_status, &rs_old->dl_status,sizeof(download_status_t)); @@ -1585,7 +1585,7 @@ networkstatus_set_current_consensus(const char *consensus, networkstatus_t *c=NULL; int r, result = -1; time_t now = time(NULL); - or_options_t *options = get_options(); + const or_options_t *options = get_options(); char *unverified_fname = NULL, *consensus_fname = NULL; int flav = networkstatus_parse_flavor_name(flavor); const unsigned from_cache = flags & NSSET_FROM_CACHE; @@ -1668,7 +1668,7 @@ networkstatus_set_current_consensus(const char *consensus, } if (current_digests && - !memcmp(&c->digests, current_digests, sizeof(c->digests))) { + tor_memeq(&c->digests, current_digests, sizeof(c->digests))) { /* We already have this one. That's a failure. */ log_info(LD_DIR, "Got a %s consensus we already have", flavor); goto done; @@ -1814,7 +1814,7 @@ networkstatus_set_current_consensus(const char *consensus, * valid-after time, declare that our clock is skewed. */ #define EARLY_CONSENSUS_NOTICE_SKEW 60 - if (now < current_consensus->valid_after - EARLY_CONSENSUS_NOTICE_SKEW) { + if (now < c->valid_after - EARLY_CONSENSUS_NOTICE_SKEW) { char tbuf[ISO_TIME_LEN+1]; char dbuf[64]; long delta = now - c->valid_after; @@ -1991,7 +1991,7 @@ routers_update_status_from_consensus_networkstatus(smartlist_t *routers, int reset_failures) { trusted_dir_server_t *ds; - or_options_t *options = get_options(); + const or_options_t *options = get_options(); int authdir = authdir_mode_v2(options) || authdir_mode_v3(options); networkstatus_t *ns = current_consensus; if (!ns || !smartlist_len(ns->routerstatus_list)) @@ -2003,7 +2003,7 @@ routers_update_status_from_consensus_networkstatus(smartlist_t *routers, SMARTLIST_FOREACH_JOIN(ns->routerstatus_list, routerstatus_t *, rs, routers, routerinfo_t *, router, - memcmp(rs->identity_digest, + tor_memcmp(rs->identity_digest, router->cache_info.identity_digest, DIGEST_LEN), { #if 0 @@ -2020,7 +2020,7 @@ routers_update_status_from_consensus_networkstatus(smartlist_t *routers, ds = router_get_trusteddirserver_by_digest(digest); /* Is it the same descriptor, or only the same identity? */ - if (!memcmp(router->cache_info.signed_descriptor_digest, + if (tor_memeq(router->cache_info.signed_descriptor_digest, rs->descriptor_digest, DIGEST_LEN)) { if (ns->valid_until > router->cache_info.last_listed_as_valid_until) router->cache_info.last_listed_as_valid_until = ns->valid_until; @@ -2049,10 +2049,10 @@ routers_update_status_from_consensus_networkstatus(smartlist_t *routers, time_t live_until = ns->published_on + V2_NETWORKSTATUS_ROUTER_LIFETIME; SMARTLIST_FOREACH_JOIN(ns->entries, const routerstatus_t *, rs, routers, routerinfo_t *, ri, - memcmp(rs->identity_digest, + tor_memcmp(rs->identity_digest, ri->cache_info.identity_digest, DIGEST_LEN), STMT_NIL) { - if (!memcmp(ri->cache_info.signed_descriptor_digest, + if (tor_memeq(ri->cache_info.signed_descriptor_digest, rs->descriptor_digest, DIGEST_LEN)) { if (live_until > ri->cache_info.last_listed_as_valid_until) ri->cache_info.last_listed_as_valid_until = live_until; @@ -2151,7 +2151,7 @@ void networkstatus_dump_bridge_status_to_file(time_t now) { char *status = networkstatus_getinfo_by_purpose("bridge", now); - or_options_t *options = get_options(); + const or_options_t *options = get_options(); size_t len = strlen(options->DataDirectory) + 32; char *fname = tor_malloc(len); tor_snprintf(fname, len, "%s"PATH_SEPARATOR"networkstatus-bridges", @@ -2205,7 +2205,7 @@ get_net_param_from_list(smartlist_t *net_params, const char *param_name, * <b>min_val</b> and at most <b>max_val</b> and raise/cap the parsed value * if necessary. */ int32_t -networkstatus_get_param(networkstatus_t *ns, const char *param_name, +networkstatus_get_param(const networkstatus_t *ns, const char *param_name, int32_t default_val, int32_t min_val, int32_t max_val) { if (!ns) /* if they pass in null, go find it ourselves */ diff --git a/src/or/networkstatus.h b/src/or/networkstatus.h index 38fac557d..1b10f2738 100644 --- a/src/or/networkstatus.h +++ b/src/or/networkstatus.h @@ -67,7 +67,7 @@ int networkstatus_nickname_is_unnamed(const char *nickname); void networkstatus_consensus_download_failed(int status_code, const char *flavname); void update_consensus_networkstatus_fetch_time(time_t now); -int should_delay_dir_fetches(or_options_t *options); +int should_delay_dir_fetches(const or_options_t *options); void update_networkstatus_downloads(time_t now); void update_certificate_downloads(time_t now); int consensus_is_waiting_for_certs(void); @@ -96,7 +96,8 @@ void signed_descs_update_status_from_consensus_networkstatus( char *networkstatus_getinfo_helper_single(const routerstatus_t *rs); char *networkstatus_getinfo_by_purpose(const char *purpose_string, time_t now); void networkstatus_dump_bridge_status_to_file(time_t now); -int32_t networkstatus_get_param(networkstatus_t *ns, const char *param_name, +int32_t networkstatus_get_param(const networkstatus_t *ns, + const char *param_name, int32_t default_val, int32_t min_val, int32_t max_val); int getinfo_helper_networkstatus(control_connection_t *conn, diff --git a/src/or/nodelist.c b/src/or/nodelist.c index 29bd7e0d9..08131219b 100644 --- a/src/or/nodelist.c +++ b/src/or/nodelist.c @@ -47,7 +47,7 @@ node_id_hash(const node_t *node) static INLINE unsigned int node_id_eq(const node_t *node1, const node_t *node2) { - return 0 == memcmp(node1->identity, node2->identity, DIGEST_LEN); + return tor_memeq(node1->identity, node2->identity, DIGEST_LEN); } HT_PROTOTYPE(nodelist_map, node_t, ht_ent, node_id_hash, node_id_eq); @@ -175,7 +175,7 @@ nodelist_add_microdesc(microdesc_t *md) void nodelist_set_consensus(networkstatus_t *ns) { - or_options_t *options = get_options(); + const or_options_t *options = get_options(); int authdir = authdir_mode_v2(options) || authdir_mode_v3(options); init_nodelist(); @@ -187,7 +187,7 @@ nodelist_set_consensus(networkstatus_t *ns) node->rs = rs; if (ns->flavor == FLAV_MICRODESC) { if (node->md == NULL || - 0!=memcmp(node->md->digest,rs->descriptor_digest,DIGEST256_LEN)) { + tor_memneq(node->md->digest,rs->descriptor_digest,DIGEST256_LEN)) { if (node->md) node->md->held_by_node = 0; node->md = microdesc_cache_lookup_by_digest256(NULL, @@ -354,17 +354,19 @@ nodelist_assert_ok(void) { routerlist_t *rl = router_get_routerlist(); networkstatus_t *ns = networkstatus_get_latest_consensus(); - digestmap_t *dm = digestmap_new(); + digestmap_t *dm; if (!the_nodelist) return; + dm = digestmap_new(); + /* every routerinfo in rl->routers should be in the nodelist. */ if (rl) { SMARTLIST_FOREACH_BEGIN(rl->routers, routerinfo_t *, ri) { const node_t *node = node_get_by_id(ri->cache_info.identity_digest); tor_assert(node && node->ri == ri); - tor_assert(0 == memcmp(ri->cache_info.identity_digest, + tor_assert(fast_memeq(ri->cache_info.identity_digest, node->identity, DIGEST_LEN)); tor_assert(! digestmap_get(dm, node->identity)); digestmap_set(dm, node->identity, (void*)node); @@ -376,7 +378,7 @@ nodelist_assert_ok(void) SMARTLIST_FOREACH_BEGIN(ns->routerstatus_list, routerstatus_t *, rs) { const node_t *node = node_get_by_id(rs->identity_digest); tor_assert(node && node->rs == rs); - tor_assert(0 == memcmp(rs->identity_digest, node->identity, DIGEST_LEN)); + tor_assert(fast_memeq(rs->identity_digest, node->identity, DIGEST_LEN)); digestmap_set(dm, node->identity, (void*)node); if (ns->flavor == FLAV_MICRODESC) { /* If it's a microdesc consensus, every entry that has a @@ -436,7 +438,7 @@ node_get_by_hex_id(const char *hex_id) if (nn_char == '=') { const char *named_id = networkstatus_get_router_digest_by_nickname(nn_buf); - if (!named_id || memcmp(named_id, digest_buf, DIGEST_LEN)) + if (!named_id || tor_memneq(named_id, digest_buf, DIGEST_LEN)) return NULL; } } @@ -554,7 +556,7 @@ node_is_named(const node_t *node) named_id = networkstatus_get_router_digest_by_nickname(nickname); if (!named_id) return 0; - return !memcmp(named_id, node->identity, DIGEST_LEN); + return tor_memeq(named_id, node->identity, DIGEST_LEN); } /** Return true iff <b>node</b> appears to be a directory authority or diff --git a/src/or/onion.c b/src/or/onion.c index e1d10a60b..211d14c1e 100644 --- a/src/or/onion.c +++ b/src/or/onion.c @@ -328,7 +328,7 @@ onion_skin_client_handshake(crypto_dh_env_t *handshake_state, if (len < 0) goto err; - if (memcmp(key_material, handshake_reply+DH_KEY_LEN, DIGEST_LEN)) { + 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."); @@ -415,7 +415,7 @@ fast_client_handshake(const uint8_t *handshake_state,/*DIGEST_LEN bytes*/ if (crypto_expand_key_material(tmp, sizeof(tmp), out, out_len)) { goto done; } - if (memcmp(out, handshake_reply_out+DIGEST_LEN, DIGEST_LEN)) { + 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."); diff --git a/src/or/or.h b/src/or/or.h index ddc03be87..ff824468f 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -982,7 +982,7 @@ typedef struct connection_t { unsigned int proxy_state:4; /** Our socket; -1 if this connection is closed, or has no socket. */ - evutil_socket_t s; + tor_socket_t s; int conn_array_index; /**< Index into the global connection array. */ struct event *read_event; /**< Libevent event structure. */ @@ -1027,7 +1027,7 @@ typedef struct connection_t { /* XXXX023 move this field, and all the listener-only fields (just socket_family, I think), into a new listener_connection_t subtype. */ /** If the connection is a CONN_TYPE_AP_DNS_LISTENER, this field points - * to the evdns_server_port is uses to listen to and answer connections. */ + * to the evdns_server_port it uses to listen to and answer connections. */ struct evdns_server_port *dns_server_port; /** Unique ID for measuring tunneled network status requests. */ @@ -1271,6 +1271,9 @@ typedef struct control_connection_t { /** True if we have sent a protocolinfo reply on this connection. */ unsigned int have_sent_protocolinfo:1; + /** True if we have received a takeownership command on this + * connection. */ + unsigned int is_owning_control_connection:1; /** Amount of space allocated in incoming_cmd. */ uint32_t incoming_cmd_len; @@ -2194,15 +2197,15 @@ typedef struct { /** How to extend to the planned exit node. */ extend_info_t *chosen_exit; /** Whether every node in the circ must have adequate uptime. */ - int need_uptime; + unsigned int need_uptime : 1; /** Whether every node in the circ must have adequate capacity. */ - int need_capacity; + unsigned int need_capacity : 1; /** Whether the last hop was picked with exiting in mind. */ - int is_internal; - /** Did we pick this as a one-hop tunnel (not safe for other conns)? - * These are for encrypted connections that exit to this router, not + unsigned int is_internal : 1; + /** Did we pick this as a one-hop tunnel (not safe for other streams)? + * These are for encrypted dir conns that exit to this router, not * for arbitrary exits from the circuit. */ - int onehop_tunnel; + unsigned int onehop_tunnel : 1; /** The crypt_path_t to append after rendezvous: used for rendezvous. */ crypt_path_t *pending_final_cpath; /** How many times has building a circuit for this task failed? */ @@ -2310,6 +2313,11 @@ typedef struct circuit_t { * in time in order to indicate that a circuit shouldn't be used for new * streams, but that it can stay alive as long as it has streams on it. * That's a kludge we should fix. + * + * XXX023 The CBT code uses this field to record when HS-related + * circuits entered certain states. This usage probably won't + * interfere with this field's primary purpose, but we should + * document it more thoroughly to make sure of that. */ time_t timestamp_dirty; @@ -2480,14 +2488,14 @@ typedef struct or_circuit_t { cell_ewma_t p_cell_ewma; } or_circuit_t; -/** Convert a circuit subtype to a circuit_t.*/ +/** Convert a circuit subtype to a circuit_t. */ #define TO_CIRCUIT(x) (&((x)->_base)) -/** Convert a circuit_t* to a pointer to the enclosing or_circuit_t. Asserts +/** Convert a circuit_t* to a pointer to the enclosing or_circuit_t. Assert * if the cast is impossible. */ static or_circuit_t *TO_OR_CIRCUIT(circuit_t *); /** Convert a circuit_t* to a pointer to the enclosing origin_circuit_t. - * Asserts if the cast is impossible. */ + * Assert if the cast is impossible. */ static origin_circuit_t *TO_ORIGIN_CIRCUIT(circuit_t *); static INLINE or_circuit_t *TO_OR_CIRCUIT(circuit_t *x) @@ -2523,6 +2531,10 @@ typedef struct config_line_t { typedef struct routerset_t routerset_t; +/** A magic value for the (Socks|OR|...)Port options below, telling Tor + * to pick its own port. */ +#define CFG_AUTO_PORT 0xc4005e + /** Configuration options for a Tor process. */ typedef struct { uint32_t _magic; @@ -2612,6 +2624,7 @@ typedef struct { int ControlPort; /**< Port to listen on for control connections. */ config_line_t *ControlSocket; /**< List of Unix Domain Sockets to listen on * for control connections. */ + int ControlSocketsGroupWritable; /**< Boolean: Are control sockets g+rw? */ int DirPort; /**< Port to listen on for directory connections. */ int DNSPort; /**< Port to listen on for DNS requests. */ int AssumeReachable; /**< Whether to publish our descriptor regardless. */ @@ -2842,6 +2855,11 @@ typedef struct { int DisablePredictedCircuits; /**< Boolean: does Tor preemptively * make circuits in the background (0), * or not (1)? */ + + /** Process specifier for a controller that ‘owns’ this Tor + * instance. Tor will terminate if its owning controller does. */ + char *OwningControllerProcess; + int ShutdownWaitLength; /**< When we get a SIGINT and we're a server, how * long do we wait before exiting? */ char *SafeLogging; /**< Contains "relay", "1", "0" (meaning no scrubbing). */ @@ -3062,6 +3080,11 @@ typedef struct { * If -1, Tor decides. */ int UseMicrodescriptors; + /** File where we should write the ControlPort. */ + char *ControlPortWriteToFile; + /** Should that file be group-readable? */ + int ControlPortFileGroupReadable; + } or_options_t; /** Persistent state for an onion router, as saved to disk. */ @@ -3331,6 +3354,9 @@ typedef enum setopt_err_t { typedef enum { /** We're remapping this address because the controller told us to. */ ADDRMAPSRC_CONTROLLER, + /** We're remapping this address because of an AutomapHostsOnResolve + * configuration. */ + ADDRMAPSRC_AUTOMAP, /** We're remapping this address because our configuration (via torrc, the * command line, or a SETCONF command) told us to. */ ADDRMAPSRC_TORRC, diff --git a/src/or/policies.c b/src/or/policies.c index 6738b484a..1b5408c77 100644 --- a/src/or/policies.c +++ b/src/or/policies.c @@ -46,7 +46,7 @@ typedef struct policy_summary_item_t { uint16_t prt_max; /**< Highest port number to accept/reject. */ uint64_t reject_count; /**< Number of IP-Addresses that are rejected to this port range. */ - int accepted:1; /** Has this port already been accepted */ + unsigned int accepted:1; /** Has this port already been accepted */ } policy_summary_item_t; /** Private networks. This list is used in two places, once to expand the @@ -83,15 +83,15 @@ policy_expand_private(smartlist_t **policy) continue; } for (i = 0; private_nets[i]; ++i) { - addr_policy_t policy; - memcpy(&policy, p, sizeof(addr_policy_t)); - policy.is_private = 0; - policy.is_canonical = 0; - if (tor_addr_parse_mask_ports(private_nets[i], &policy.addr, - &policy.maskbits, &port_min, &port_max)<0) { + addr_policy_t newpolicy; + memcpy(&newpolicy, p, sizeof(addr_policy_t)); + newpolicy.is_private = 0; + newpolicy.is_canonical = 0; + if (tor_addr_parse_mask_ports(private_nets[i], &newpolicy.addr, + &newpolicy.maskbits, &port_min, &port_max)<0) { tor_assert(0); } - smartlist_add(tmp, addr_policy_get_canonical_entry(&policy)); + smartlist_add(tmp, addr_policy_get_canonical_entry(&newpolicy)); } addr_policy_free(p); }); @@ -164,7 +164,7 @@ parse_addr_policy(config_line_t *cfg, smartlist_t **dest, static int parse_reachable_addresses(void) { - or_options_t *options = get_options(); + const or_options_t *options = get_options(); int ret = 0; if (options->ReachableDirAddresses && @@ -356,7 +356,7 @@ authdir_policy_badexit_address(uint32_t addr, uint16_t port) * options in <b>options</b>, return -1 and set <b>msg</b> to a newly * allocated description of the error. Else return 0. */ int -validate_addr_policies(or_options_t *options, char **msg) +validate_addr_policies(const or_options_t *options, char **msg) { /* XXXX Maybe merge this into parse_policies_from_options, to make sure * that the two can't go out of sync. */ @@ -440,7 +440,7 @@ load_policy_from_option(config_line_t *config, smartlist_t **policy, /** Set all policies based on <b>options</b>, which should have been validated * first by validate_addr_policies. */ int -policies_parse_from_options(or_options_t *options) +policies_parse_from_options(const or_options_t *options) { int ret = 0; if (load_policy_from_option(options->SocksPolicy, &socks_policy, -1) < 0) diff --git a/src/or/policies.h b/src/or/policies.h index ee1162ccc..6f3624aba 100644 --- a/src/or/policies.h +++ b/src/or/policies.h @@ -29,9 +29,9 @@ int authdir_policy_valid_address(uint32_t addr, uint16_t port); int authdir_policy_baddir_address(uint32_t addr, uint16_t port); int authdir_policy_badexit_address(uint32_t addr, uint16_t port); -int validate_addr_policies(or_options_t *options, char **msg); +int validate_addr_policies(const or_options_t *options, char **msg); void policy_expand_private(smartlist_t **policy); -int policies_parse_from_options(or_options_t *options); +int policies_parse_from_options(const or_options_t *options); addr_policy_t *addr_policy_get_canonical_entry(addr_policy_t *ent); int cmp_addr_policies(smartlist_t *a, smartlist_t *b); diff --git a/src/or/relay.c b/src/or/relay.c index e5bc310fe..df6d0a8a5 100644 --- a/src/or/relay.c +++ b/src/or/relay.c @@ -29,6 +29,7 @@ #include "reasons.h" #include "relay.h" #include "rendcommon.h" +#include "router.h" #include "routerlist.h" #include "routerparse.h" @@ -134,7 +135,7 @@ relay_digest_matches(crypto_digest_env_t *digest, cell_t *cell) crypto_digest_add_bytes(digest, (char*) cell->payload, CELL_PAYLOAD_SIZE); crypto_digest_get_digest(digest, calculated_integrity, 4); - if (memcmp(received_integrity, calculated_integrity, 4)) { + if (tor_memneq(received_integrity, calculated_integrity, 4)) { // log_fn(LOG_INFO,"Recognized=0 but bad digest. Not recognizing."); // (%d vs %d).", received_integrity, calculated_integrity); /* restore digest to its old form */ @@ -751,9 +752,9 @@ connection_ap_process_end_not_open( (tor_inet_aton(conn->socks_request->address, &in) && !conn->chosen_exit_name))) { log_info(LD_APP, - "Exitrouter '%s' seems to be more restrictive than its exit " + "Exitrouter %s seems to be more restrictive than its exit " "policy. Not using this router as exit for now.", - node_get_nickname(exitrouter)); + node_describe(exitrouter)); policies_set_node_exitpolicy_to_reject_all(exitrouter); } /* rewrite it to an IP if we learned one. */ @@ -2009,7 +2010,8 @@ static int ewma_enabled = 0; /** Adjust the global cell scale factor based on <b>options</b> */ void -cell_ewma_set_scale_factor(or_options_t *options, networkstatus_t *consensus) +cell_ewma_set_scale_factor(const or_options_t *options, + const networkstatus_t *consensus) { int32_t halflife_ms; double halflife; @@ -2335,13 +2337,13 @@ connection_or_flush_from_first_active_circuit(or_connection_t *conn, int max, /* Calculate the exact time that this cell has spent in the queue. */ if (get_options()->CellStatistics && !CIRCUIT_IS_ORIGIN(circ)) { - struct timeval now; + struct timeval tvnow; uint32_t flushed; uint32_t cell_waiting_time; insertion_time_queue_t *it_queue = queue->insertion_times; - tor_gettimeofday_cached(&now); - flushed = (uint32_t)((now.tv_sec % SECONDS_IN_A_DAY) * 100L + - (uint32_t)now.tv_usec / (uint32_t)10000L); + tor_gettimeofday_cached(&tvnow); + flushed = (uint32_t)((tvnow.tv_sec % SECONDS_IN_A_DAY) * 100L + + (uint32_t)tvnow.tv_usec / (uint32_t)10000L); if (!it_queue || !it_queue->first) { log_info(LD_GENERAL, "Cannot determine insertion time of cell. " "Looks like the CellStatistics option was " diff --git a/src/or/relay.h b/src/or/relay.h index f64752da5..7fce8edca 100644 --- a/src/or/relay.h +++ b/src/or/relay.h @@ -60,8 +60,8 @@ const uint8_t *decode_address_from_payload(tor_addr_t *addr_out, const uint8_t *payload, int payload_len); unsigned cell_ewma_get_tick(void); -void cell_ewma_set_scale_factor(or_options_t *options, - networkstatus_t *consensus); +void cell_ewma_set_scale_factor(const or_options_t *options, + const networkstatus_t *consensus); void circuit_clear_cell_queue(circuit_t *circ, or_connection_t *orconn); void tor_gettimeofday_cache_clear(void); diff --git a/src/or/rendclient.c b/src/or/rendclient.c index 838b8f742..b618d0fe4 100644 --- a/src/or/rendclient.c +++ b/src/or/rendclient.c @@ -21,12 +21,23 @@ #include "rendclient.h" #include "rendcommon.h" #include "rephist.h" +#include "router.h" #include "routerlist.h" static extend_info_t *rend_client_get_random_intro_impl( const rend_cache_entry_t *rend_query, const int strict, const int warnings); +/** Purge all potentially remotely-detectable state held in the hidden + * service client code. Called on SIGNAL NEWNYM. */ +void +rend_client_purge_state(void) +{ + rend_cache_purge(); + rend_client_cancel_descriptor_fetches(); + rend_client_purge_last_hid_serv_requests(); +} + /** Called when we've established a circuit to an introduction point: * send the introduction request. */ void @@ -91,12 +102,13 @@ rend_client_reextend_intro_circuit(origin_circuit_t *circ) if (circ->remaining_relay_early_cells) { log_info(LD_REND, "Re-extending circ %d, this time to %s.", - circ->_base.n_circ_id, extend_info->nickname); + circ->_base.n_circ_id, + safe_str_client(extend_info_describe(extend_info))); result = circuit_extend_to_new_exit(circ, extend_info); } else { log_info(LD_REND, "Building a new introduction circuit, this time to %s.", - extend_info->nickname); + safe_str_client(extend_info_describe(extend_info))); circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_FINISHED); if (!circuit_launch_by_extend_info(CIRCUIT_PURPOSE_C_INTRODUCING, extend_info, @@ -133,6 +145,8 @@ rend_client_send_introduction(origin_circuit_t *introcirc, tor_assert(rendcirc->rend_data); tor_assert(!rend_cmp_service_ids(introcirc->rend_data->onion_address, rendcirc->rend_data->onion_address)); + tor_assert(!(introcirc->build_state->onehop_tunnel)); + tor_assert(!(rendcirc->build_state->onehop_tunnel)); if (rend_cache_lookup_entry(introcirc->rend_data->onion_address, -1, &entry) < 1) { @@ -158,7 +172,7 @@ rend_client_send_introduction(origin_circuit_t *introcirc, intro_key = NULL; SMARTLIST_FOREACH(entry->parsed->intro_nodes, rend_intro_point_t *, intro, { - if (!memcmp(introcirc->build_state->chosen_exit->identity_digest, + if (tor_memeq(introcirc->build_state->chosen_exit->identity_digest, intro->extend_info->identity_digest, DIGEST_LEN)) { intro_key = intro->intro_key; break; @@ -169,7 +183,8 @@ rend_client_send_introduction(origin_circuit_t *introcirc, "have a v2 rend desc with %d intro points. " "Trying a different intro point...", safe_str_client(introcirc->rend_data->onion_address), - introcirc->build_state->chosen_exit->nickname, + safe_str_client(extend_info_describe( + introcirc->build_state->chosen_exit)), smartlist_len(entry->parsed->intro_nodes)); if (rend_client_reextend_intro_circuit(introcirc)) { @@ -276,6 +291,10 @@ rend_client_send_introduction(origin_circuit_t *introcirc, /* Now, we wait for an ACK or NAK on this circuit. */ introcirc->_base.purpose = CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT; + /* Set timestamp_dirty, because circuit_expire_building expects it + * to specify when a circuit entered the _C_INTRODUCE_ACK_WAIT + * state. */ + introcirc->_base.timestamp_dirty = time(NULL); return 0; perm_err: @@ -318,6 +337,7 @@ rend_client_introduction_acked(origin_circuit_t *circ, } tor_assert(circ->build_state->chosen_exit); + tor_assert(!(circ->build_state->onehop_tunnel)); tor_assert(circ->rend_data); if (request_len == 0) { @@ -329,7 +349,12 @@ rend_client_introduction_acked(origin_circuit_t *circ, rendcirc = circuit_get_by_rend_query_and_purpose( circ->rend_data->onion_address, CIRCUIT_PURPOSE_C_REND_READY); if (rendcirc) { /* remember the ack */ + tor_assert(!(rendcirc->build_state->onehop_tunnel)); rendcirc->_base.purpose = CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED; + /* Set timestamp_dirty, because circuit_expire_building expects + * it to specify when a circuit entered the + * _C_REND_READY_INTRO_ACKED state. */ + rendcirc->_base.timestamp_dirty = time(NULL); } else { log_info(LD_REND,"...Found no rend circ. Dropping on the floor."); } @@ -344,8 +369,8 @@ rend_client_introduction_acked(origin_circuit_t *circ, * If none remain, refetch the service descriptor. */ log_info(LD_REND, "Got nack for %s from %s...", - safe_str_client(circ->rend_data->onion_address), - circ->build_state->chosen_exit->nickname); + safe_str_client(circ->rend_data->onion_address), + safe_str_client(extend_info_describe(circ->build_state->chosen_exit))); if (rend_client_remove_intro_point(circ->build_state->chosen_exit, circ->rend_data) > 0) { /* There are introduction points left. Re-extend the circuit to @@ -367,7 +392,17 @@ rend_client_introduction_acked(origin_circuit_t *circ, * certain queries; keys are strings consisting of base32-encoded * hidden service directory identities and base32-encoded descriptor IDs; * values are pointers to timestamps of the last requests. */ -static strmap_t *last_hid_serv_requests = NULL; +static strmap_t *last_hid_serv_requests_ = NULL; + +/** Returns last_hid_serv_requests_, initializing it to a new strmap if + * necessary. */ +static strmap_t * +get_last_hid_serv_requests(void) +{ + if (!last_hid_serv_requests_) + last_hid_serv_requests_ = strmap_new(); + return last_hid_serv_requests_; +} /** Look up the last request time to hidden service directory <b>hs_dir</b> * for descriptor ID <b>desc_id_base32</b>. If <b>set</b> is non-zero, @@ -381,6 +416,7 @@ lookup_last_hid_serv_request(routerstatus_t *hs_dir, char hsdir_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1]; char hsdir_desc_comb_id[2 * REND_DESC_ID_V2_LEN_BASE32 + 1]; time_t *last_request_ptr; + strmap_t *last_hid_serv_requests = get_last_hid_serv_requests(); base32_encode(hsdir_id_base32, sizeof(hsdir_id_base32), hs_dir->identity_digest, DIGEST_LEN); tor_snprintf(hsdir_desc_comb_id, sizeof(hsdir_desc_comb_id), "%s%s", @@ -406,8 +442,7 @@ directory_clean_last_hid_serv_requests(time_t now) { strmap_iter_t *iter; time_t cutoff = now - REND_HID_SERV_DIR_REQUERY_PERIOD; - if (!last_hid_serv_requests) - last_hid_serv_requests = strmap_new(); + strmap_t *last_hid_serv_requests = get_last_hid_serv_requests(); for (iter = strmap_iter_init(last_hid_serv_requests); !strmap_iter_done(iter); ) { const char *key; @@ -424,6 +459,26 @@ directory_clean_last_hid_serv_requests(time_t now) } } +/** Purge the history of request times to hidden service directories, + * so that future lookups of an HS descriptor will not fail because we + * accessed all of the HSDir relays responsible for the descriptor + * recently. */ +void +rend_client_purge_last_hid_serv_requests(void) +{ + /* Don't create the table if it doesn't exist yet (and it may very + * well not exist if the user hasn't accessed any HSes)... */ + strmap_t *old_last_hid_serv_requests = last_hid_serv_requests_; + /* ... and let get_last_hid_serv_requests re-create it for us if + * necessary. */ + last_hid_serv_requests_ = NULL; + + if (old_last_hid_serv_requests != NULL) { + log_info(LD_REND, "Purging client last-HS-desc-request-time table"); + strmap_free(old_last_hid_serv_requests, _tor_free); + } +} + /** Determine the responsible hidden service directories for <b>desc_id</b> * and fetch the descriptor belonging to that ID from one of them. Only * send a request to hidden service directories that we did not try within @@ -500,12 +555,12 @@ directory_get_from_hs_dir(const char *desc_id, const rend_data_t *rend_query) log_info(LD_REND, "Sending fetch request for v2 descriptor for " "service '%s' with descriptor ID '%s', auth type %d, " "and descriptor cookie '%s' to hidden service " - "directory '%s' on port %d.", + "directory %s", rend_query->onion_address, desc_id_base32, rend_query->auth_type, (rend_query->auth_type == REND_NO_AUTH ? "[none]" : - escaped_safe_str_client(descriptor_cookie_base64)), - hs_dir->nickname, hs_dir->dir_port); + escaped_safe_str_client(descriptor_cookie_base64)), + routerstatus_describe(hs_dir)); return 1; } @@ -629,7 +684,7 @@ rend_client_remove_intro_point(extend_info_t *failed_intro, for (i = 0; i < smartlist_len(ent->parsed->intro_nodes); i++) { rend_intro_point_t *intro = smartlist_get(ent->parsed->intro_nodes, i); - if (!memcmp(failed_intro->identity_digest, + if (tor_memeq(failed_intro->identity_digest, intro->extend_info->identity_digest, DIGEST_LEN)) { rend_intro_point_free(intro); smartlist_del(ent->parsed->intro_nodes, i); @@ -677,6 +732,9 @@ rend_client_rendezvous_acked(origin_circuit_t *circ, const uint8_t *request, log_info(LD_REND,"Got rendezvous ack. This circuit is now ready for " "rendezvous."); circ->_base.purpose = CIRCUIT_PURPOSE_C_REND_READY; + /* Set timestamp_dirty, because circuit_expire_building expects it + * to specify when a circuit entered the _C_REND_READY state. */ + circ->_base.timestamp_dirty = time(NULL); /* XXXX023 This is a pretty brute-force approach. It'd be better to * attach only the connections that are waiting on this circuit, rather * than trying to attach them all. See comments bug 743. */ @@ -728,7 +786,7 @@ rend_client_receive_rendezvous(origin_circuit_t *circ, const uint8_t *request, goto err; /* Check whether the digest is right... */ - if (memcmp(keys, request+DH_KEY_LEN, DIGEST_LEN)) { + if (tor_memneq(keys, request+DH_KEY_LEN, DIGEST_LEN)) { log_warn(LD_PROTOCOL, "Incorrect digest of key material."); goto err; } @@ -849,7 +907,7 @@ rend_client_get_random_intro_impl(const rend_cache_entry_t *entry, int i; rend_intro_point_t *intro; - or_options_t *options = get_options(); + const or_options_t *options = get_options(); smartlist_t *usable_nodes; int n_excluded = 0; @@ -956,7 +1014,8 @@ rend_service_authorization_free_all(void) * service and add it to the local map of hidden service authorizations. * Return 0 for success and -1 for failure. */ int -rend_parse_service_authorization(or_options_t *options, int validate_only) +rend_parse_service_authorization(const or_options_t *options, + int validate_only) { config_line_t *line; int res = -1; diff --git a/src/or/rendclient.h b/src/or/rendclient.h index 6910c1a97..1893fd952 100644 --- a/src/or/rendclient.h +++ b/src/or/rendclient.h @@ -12,6 +12,8 @@ #ifndef _TOR_RENDCLIENT_H #define _TOR_RENDCLIENT_H +void rend_client_purge_state(void); + void rend_client_introcirc_has_opened(origin_circuit_t *circ); void rend_client_rendcirc_has_opened(origin_circuit_t *circ); int rend_client_introduction_acked(origin_circuit_t *circ, @@ -19,6 +21,7 @@ int rend_client_introduction_acked(origin_circuit_t *circ, size_t request_len); void rend_client_refetch_v2_renddesc(const rend_data_t *rend_query); void rend_client_cancel_descriptor_fetches(void); +void rend_client_purge_last_hid_serv_requests(void); int rend_client_remove_intro_point(extend_info_t *failed_intro, const rend_data_t *rend_query); int rend_client_rendezvous_acked(origin_circuit_t *circ, @@ -34,7 +37,7 @@ int rend_client_any_intro_points_usable(const rend_cache_entry_t *entry); int rend_client_send_introduction(origin_circuit_t *introcirc, origin_circuit_t *rendcirc); -int rend_parse_service_authorization(or_options_t *options, +int rend_parse_service_authorization(const or_options_t *options, int validate_only); rend_service_authorization_t *rend_client_lookup_service_authorization( const char *onion_address); diff --git a/src/or/rendcommon.c b/src/or/rendcommon.c index 3ee7419d7..94bb00221 100644 --- a/src/or/rendcommon.c +++ b/src/or/rendcommon.c @@ -838,8 +838,10 @@ rend_cache_clean(time_t now) void rend_cache_purge(void) { - if (rend_cache) + if (rend_cache) { + log_info(LD_REND, "Purging client/v0-HS-authority HS descriptor cache"); strmap_free(rend_cache, _rend_cache_entry_free); + } rend_cache = strmap_new(); } @@ -884,15 +886,15 @@ rend_id_is_in_interval(const char *a, const char *b, const char *c) tor_assert(c); /* There are five cases in which a is outside the interval ]b,c]: */ - a_b = memcmp(a,b,DIGEST_LEN); + a_b = tor_memcmp(a,b,DIGEST_LEN); if (a_b == 0) return 0; /* 1. a == b (b is excluded) */ - b_c = memcmp(b,c,DIGEST_LEN); + b_c = tor_memcmp(b,c,DIGEST_LEN); if (b_c == 0) return 0; /* 2. b == c (interval is empty) */ else if (a_b <= 0 && b_c < 0) return 0; /* 3. a b c */ - c_a = memcmp(c,a,DIGEST_LEN); + c_a = tor_memcmp(c,a,DIGEST_LEN); if (c_a < 0 && a_b <= 0) return 0; /* 4. c a b */ else if (b_c < 0 && c_a < 0) @@ -981,15 +983,10 @@ rend_cache_lookup_v2_desc_as_dir(const char *desc_id, const char **desc) tor_assert(rend_cache_v2_dir); if (base32_decode(desc_id_digest, DIGEST_LEN, desc_id, REND_DESC_ID_V2_LEN_BASE32) < 0) { - log_warn(LD_REND, "Descriptor ID contains illegal characters: %s", - safe_str(desc_id)); - return -1; - } - /* Determine if we are responsible. */ - if (hid_serv_responsible_for_desc_id(desc_id_digest) < 0) { - log_info(LD_REND, "Could not answer fetch request for v2 descriptor; " - "either we are no hidden service directory, or we are " - "not responsible for the requested ID."); + log_fn(LOG_PROTOCOL_WARN, LD_REND, + "Rejecting v2 rendezvous descriptor request -- descriptor ID " + "contains illegal characters: %s", + safe_str(desc_id)); return -1; } /* Lookup descriptor and return. */ @@ -1014,9 +1011,14 @@ rend_cache_lookup_v2_desc_as_dir(const char *desc_id, const char **desc) * * The published flag tells us if we store the descriptor * in our role as directory (1) or if we cache it as client (0). + * + * If <b>service_id</b> is non-NULL and the descriptor is not for that + * service ID, reject it. <b>service_id</b> must be specified if and + * only if <b>published</b> is 0 (we fetched this descriptor). */ int -rend_cache_store(const char *desc, size_t desc_len, int published) +rend_cache_store(const char *desc, size_t desc_len, int published, + const char *service_id) { rend_cache_entry_t *e; rend_service_descriptor_t *parsed; @@ -1034,6 +1036,13 @@ rend_cache_store(const char *desc, size_t desc_len, int published) rend_service_descriptor_free(parsed); return -2; } + if ((service_id != NULL) && strcmp(query, service_id)) { + log_warn(LD_REND, "Received service descriptor for service ID %s; " + "expected descriptor for service ID %s.", + query, safe_str(service_id)); + rend_service_descriptor_free(parsed); + return -2; + } now = time(NULL); if (parsed->timestamp < now-REND_CACHE_MAX_AGE-REND_CACHE_MAX_SKEW) { log_fn(LOG_PROTOCOL_WARN, LD_REND, @@ -1066,7 +1075,7 @@ rend_cache_store(const char *desc, size_t desc_len, int published) rend_service_descriptor_free(parsed); return 0; } - if (e && e->len == desc_len && !memcmp(desc,e->desc,desc_len)) { + if (e && e->len == desc_len && tor_memeq(desc,e->desc,desc_len)) { log_info(LD_REND,"We already have this service descriptor %s.", safe_str_client(query)); e->received = time(NULL); @@ -1214,6 +1223,8 @@ rend_cache_store_v2_desc_as_dir(const char *desc) * If we have an older descriptor with the same ID, replace it. * If we have any v0 descriptor with the same ID, reject this one in order * to not get confused with having both versions for the same service. + * If the descriptor's service ID does not match + * <b>rend_query</b>-\>onion_address, reject it. * Return -2 if it's malformed or otherwise rejected; return -1 if we * already have a v0 descriptor here; return 0 if it's the same or older * than one we've already got; return 1 if it's novel. @@ -1264,6 +1275,13 @@ rend_cache_store_v2_desc_as_client(const char *desc, retval = -2; goto err; } + if (strcmp(rend_query->onion_address, service_id)) { + log_warn(LD_REND, "Received service descriptor for service ID %s; " + "expected descriptor for service ID %s.", + service_id, safe_str(rend_query->onion_address)); + retval = -2; + goto err; + } /* Decode/decrypt introduction points. */ if (intro_content) { if (rend_query->auth_type != REND_NO_AUTH && diff --git a/src/or/rendcommon.h b/src/or/rendcommon.h index 18d42b8c9..0d64466db 100644 --- a/src/or/rendcommon.h +++ b/src/or/rendcommon.h @@ -44,7 +44,8 @@ int rend_cache_lookup_desc(const char *query, int version, const char **desc, int rend_cache_lookup_entry(const char *query, int version, rend_cache_entry_t **entry_out); int rend_cache_lookup_v2_desc_as_dir(const char *query, const char **desc); -int rend_cache_store(const char *desc, size_t desc_len, int published); +int rend_cache_store(const char *desc, size_t desc_len, int published, + const char *service_id); int rend_cache_store_v2_desc_as_client(const char *desc, const rend_data_t *rend_query); int rend_cache_store_v2_desc_as_dir(const char *desc); diff --git a/src/or/rendmid.c b/src/or/rendmid.c index 5e2dd986b..04edd8e3e 100644 --- a/src/or/rendmid.c +++ b/src/or/rendmid.c @@ -62,7 +62,7 @@ rend_mid_establish_intro(or_circuit_t *circ, const uint8_t *request, log_warn(LD_BUG, "Internal error computing digest."); goto err; } - if (memcmp(expected_digest, request+2+asn1len, DIGEST_LEN)) { + if (tor_memneq(expected_digest, request+2+asn1len, DIGEST_LEN)) { log_warn(LD_PROTOCOL, "Hash of session info was not as expected."); reason = END_CIRC_REASON_TORPROTOCOL; goto err; diff --git a/src/or/rendservice.c b/src/or/rendservice.c index 767712c32..4413ae9d8 100644 --- a/src/or/rendservice.c +++ b/src/or/rendservice.c @@ -182,6 +182,31 @@ rend_add_service(rend_service_t *service) log_warn(LD_CONFIG, "Hidden service with no ports configured; ignoring."); rend_service_free(service); } else { + int dupe = 0; + /* XXX This duplicate check has two problems: + * + * a) It's O(n^2), but the same comment from the bottom of + * rend_config_services() should apply. + * + * b) We only compare directory paths as strings, so we can't + * detect two distinct paths that specify the same directory + * (which can arise from symlinks, case-insensitivity, bind + * mounts, etc.). + * + * It also can't detect that two separate Tor instances are trying + * to use the same HiddenServiceDir; for that, we would need a + * lock file. But this is enough to detect a simple mistake that + * at least one person has actually made. + */ + SMARTLIST_FOREACH(rend_service_list, rend_service_t*, ptr, + dupe = dupe || + !strcmp(ptr->directory, service->directory)); + if (dupe) { + log_warn(LD_REND, "Another hidden service is already configured for " + "directory %s, ignoring.", service->directory); + rend_service_free(service); + return; + } smartlist_add(rend_service_list, service); log_debug(LD_REND,"Configuring service with directory \"%s\"", service->directory); @@ -267,7 +292,7 @@ parse_port_config(const char *string) * normal, but don't actually change the configured services.) */ int -rend_config_services(or_options_t *options, int validate_only) +rend_config_services(const or_options_t *options, int validate_only) { config_line_t *line; rend_service_t *service = NULL; @@ -466,7 +491,7 @@ rend_config_services(or_options_t *options, int validate_only) int keep_it = 0; tor_assert(oc->rend_data); SMARTLIST_FOREACH(surviving_services, rend_service_t *, ptr, { - if (!memcmp(ptr->pk_digest, oc->rend_data->rend_pk_digest, + if (tor_memeq(ptr->pk_digest, oc->rend_data->rend_pk_digest, DIGEST_LEN)) { keep_it = 1; break; @@ -475,7 +500,8 @@ rend_config_services(or_options_t *options, int validate_only) if (keep_it) continue; log_info(LD_REND, "Closing intro point %s for service %s.", - safe_str_client(oc->build_state->chosen_exit->nickname), + safe_str_client(extend_info_describe( + oc->build_state->chosen_exit)), oc->rend_data->onion_address); circuit_mark_for_close(circ, END_CIRC_REASON_FINISHED); /* XXXX Is there another reason we should use here? */ @@ -544,7 +570,7 @@ rend_service_load_keys(void) s->directory); /* Check/create directory */ - if (check_private_dir(s->directory, CPD_CREATE) < 0) + if (check_private_dir(s->directory, CPD_CREATE, get_options()->User) < 0) return -1; /* Load key */ @@ -761,7 +787,7 @@ static rend_service_t * rend_service_get_by_pk_digest(const char* digest) { SMARTLIST_FOREACH(rend_service_list, rend_service_t*, s, - if (!memcmp(s->pk_digest,digest,DIGEST_LEN)) + if (tor_memeq(s->pk_digest,digest,DIGEST_LEN)) return s); return NULL; } @@ -801,7 +827,7 @@ rend_check_authorization(rend_service_t *service, /* Look up client authorization by descriptor cookie. */ SMARTLIST_FOREACH(service->clients, rend_authorized_client_t *, client, { - if (!memcmp(client->descriptor_cookie, descriptor_cookie, + if (tor_memeq(client->descriptor_cookie, descriptor_cookie, REND_DESC_COOKIE_LEN)) { auth_client = client; break; @@ -877,8 +903,9 @@ rend_service_introduce(origin_circuit_t *circuit, const uint8_t *request, time_t now = time(NULL); char diffie_hellman_hash[DIGEST_LEN]; time_t *access_time; - or_options_t *options = get_options(); + const or_options_t *options = get_options(); + tor_assert(!(circuit->build_state->onehop_tunnel)); tor_assert(circuit->rend_data); base32_encode(serviceid, REND_SERVICE_ID_LEN_BASE32+1, @@ -915,7 +942,7 @@ rend_service_introduce(origin_circuit_t *circuit, const uint8_t *request, /* first DIGEST_LEN bytes of request is intro or service pk digest */ crypto_pk_get_digest(intro_key, intro_key_digest); - if (memcmp(intro_key_digest, request, DIGEST_LEN)) { + if (tor_memneq(intro_key_digest, request, DIGEST_LEN)) { base32_encode(serviceid, REND_SERVICE_ID_LEN_BASE32+1, (char*)request, REND_SERVICE_ID_LEN); log_warn(LD_REND, "Got an INTRODUCE2 cell for the wrong service (%s).", @@ -1147,7 +1174,7 @@ rend_service_introduce(origin_circuit_t *circuit, const uint8_t *request, if (!launched) { /* give up */ log_warn(LD_REND, "Giving up launching first hop of circuit to rendezvous " "point %s for service %s.", - escaped_safe_str_client(extend_info->nickname), + safe_str_client(extend_info_describe(extend_info)), serviceid); reason = END_CIRC_REASON_CONNECTFAILED; goto err; @@ -1155,7 +1182,7 @@ rend_service_introduce(origin_circuit_t *circuit, const uint8_t *request, log_info(LD_REND, "Accepted intro; launching circuit to %s " "(cookie %s) for service %s.", - escaped_safe_str_client(extend_info->nickname), + safe_str_client(extend_info_describe(extend_info)), hexcookie, serviceid); tor_assert(launched->build_state); /* Fill in the circuit's state. */ @@ -1207,7 +1234,8 @@ rend_service_relaunch_rendezvous(origin_circuit_t *oldcirc) "Attempt to build circuit to %s for rendezvous has failed " "too many times or expired; giving up.", oldcirc->build_state ? - oldcirc->build_state->chosen_exit->nickname : "*unknown*"); + safe_str(extend_info_describe(oldcirc->build_state->chosen_exit)) + : "*unknown*"); return; } @@ -1221,7 +1249,7 @@ rend_service_relaunch_rendezvous(origin_circuit_t *oldcirc) } log_info(LD_REND,"Reattempting rendezvous circuit to '%s'", - oldstate->chosen_exit->nickname); + safe_str(extend_info_describe(oldstate->chosen_exit))); newcirc = circuit_launch_by_extend_info(CIRCUIT_PURPOSE_S_CONNECT_REND, oldstate->chosen_exit, @@ -1229,7 +1257,7 @@ rend_service_relaunch_rendezvous(origin_circuit_t *oldcirc) if (!newcirc) { log_warn(LD_REND,"Couldn't relaunch rendezvous circuit to '%s'.", - oldstate->chosen_exit->nickname); + safe_str(extend_info_describe(oldstate->chosen_exit))); return; } newstate = newcirc->build_state; @@ -1253,7 +1281,7 @@ rend_service_launch_establish_intro(rend_service_t *service, log_info(LD_REND, "Launching circuit to introduction point %s for service %s", - escaped_safe_str_client(intro->extend_info->nickname), + safe_str_client(extend_info_describe(intro->extend_info)), service->service_id); rep_hist_note_used_internal(time(NULL), 1, 0); @@ -1266,11 +1294,11 @@ rend_service_launch_establish_intro(rend_service_t *service, if (!launched) { log_info(LD_REND, "Can't launch circuit to establish introduction at %s.", - escaped_safe_str_client(intro->extend_info->nickname)); + safe_str_client(extend_info_describe(intro->extend_info))); return -1; } - if (memcmp(intro->extend_info->identity_digest, + if (tor_memneq(intro->extend_info->identity_digest, launched->build_state->chosen_exit->identity_digest, DIGEST_LEN)) { char cann[HEX_DIGEST_LEN+1], orig[HEX_DIGEST_LEN+1]; base16_encode(cann, sizeof(cann), @@ -1332,6 +1360,7 @@ rend_service_intro_has_opened(origin_circuit_t *circuit) crypto_pk_env_t *intro_key; tor_assert(circuit->_base.purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO); + tor_assert(!(circuit->build_state->onehop_tunnel)); tor_assert(circuit->cpath); tor_assert(circuit->rend_data); @@ -1350,7 +1379,7 @@ rend_service_intro_has_opened(origin_circuit_t *circuit) /* If we already have enough introduction circuits for this service, * redefine this one as a general circuit or close it, depending. */ if (count_established_intro_points(serviceid) > NUM_INTRO_POINTS) { - or_options_t *options = get_options(); + const or_options_t *options = get_options(); if (options->ExcludeNodes) { /* XXXX in some future version, we can test whether the transition is allowed or not given the actual nodes in the circuit. But for now, @@ -1474,6 +1503,7 @@ rend_service_rendezvous_has_opened(origin_circuit_t *circuit) tor_assert(circuit->_base.purpose == CIRCUIT_PURPOSE_S_CONNECT_REND); tor_assert(circuit->cpath); tor_assert(circuit->build_state); + tor_assert(!(circuit->build_state->onehop_tunnel)); tor_assert(circuit->rend_data); hop = circuit->build_state->pending_final_cpath; tor_assert(hop); @@ -1556,7 +1586,7 @@ find_intro_circuit(rend_intro_point_t *intro, const char *pk_digest) tor_assert(intro); while ((circ = circuit_get_next_by_pk_and_purpose(circ,pk_digest, CIRCUIT_PURPOSE_S_INTRO))) { - if (!memcmp(circ->build_state->chosen_exit->identity_digest, + if (tor_memeq(circ->build_state->chosen_exit->identity_digest, intro->extend_info->identity_digest, DIGEST_LEN) && circ->rend_data) { return circ; @@ -1566,7 +1596,7 @@ find_intro_circuit(rend_intro_point_t *intro, const char *pk_digest) circ = NULL; while ((circ = circuit_get_next_by_pk_and_purpose(circ,pk_digest, CIRCUIT_PURPOSE_S_ESTABLISH_INTRO))) { - if (!memcmp(circ->build_state->chosen_exit->identity_digest, + if (tor_memeq(circ->build_state->chosen_exit->identity_digest, intro->extend_info->identity_digest, DIGEST_LEN) && circ->rend_data) { return circ; @@ -1609,9 +1639,9 @@ directory_post_to_hs_dir(rend_service_descriptor_t *renddesc, continue; if (!router_get_by_id_digest(hs_dir->identity_digest)) { log_info(LD_REND, "Not sending publish request for v2 descriptor to " - "hidden service directory '%s'; we don't have its " + "hidden service directory %s; we don't have its " "router descriptor. Queuing for later upload.", - hs_dir->nickname); + safe_str_client(routerstatus_describe(hs_dir))); failed_upload = -1; continue; } @@ -1790,7 +1820,7 @@ rend_services_introduce(void) int changed, prev_intro_nodes; smartlist_t *intro_nodes; time_t now; - or_options_t *options = get_options(); + const or_options_t *options = get_options(); intro_nodes = smartlist_create(); now = time(NULL); @@ -1819,11 +1849,12 @@ rend_services_introduce(void) node = node_get_by_id(intro->extend_info->identity_digest); if (!node || !find_intro_circuit(intro, service->pk_digest)) { log_info(LD_REND,"Giving up on %s as intro point for %s.", - intro->extend_info->nickname, service->service_id); + safe_str_client(extend_info_describe(intro->extend_info)), + safe_str_client(service->service_id)); if (service->desc) { SMARTLIST_FOREACH(service->desc->intro_nodes, rend_intro_point_t *, dintro, { - if (!memcmp(dintro->extend_info->identity_digest, + if (tor_memeq(dintro->extend_info->identity_digest, intro->extend_info->identity_digest, DIGEST_LEN)) { log_info(LD_REND, "The intro point we are giving up on was " "included in the last published descriptor. " @@ -1885,7 +1916,8 @@ rend_services_introduce(void) tor_assert(!crypto_pk_generate_key(intro->intro_key)); smartlist_add(service->intro_nodes, intro); log_info(LD_REND, "Picked router %s as an intro point for %s.", - node_get_nickname(node), service->service_id); + safe_str_client(node_describe(node)), + safe_str_client(service->service_id)); } /* If there's no need to launch new circuits, stop here. */ @@ -1898,7 +1930,8 @@ rend_services_introduce(void) r = rend_service_launch_establish_intro(service, intro); if (r<0) { log_warn(LD_REND, "Error launching circuit to node %s for service %s.", - intro->extend_info->nickname, service->service_id); + safe_str_client(extend_info_describe(intro->extend_info)), + safe_str_client(service->service_id)); } } } diff --git a/src/or/rendservice.h b/src/or/rendservice.h index 70389afe9..8a2994c4c 100644 --- a/src/or/rendservice.h +++ b/src/or/rendservice.h @@ -13,7 +13,7 @@ #define _TOR_RENDSERVICE_H int num_rend_services(void); -int rend_config_services(or_options_t *options, int validate_only); +int rend_config_services(const or_options_t *options, int validate_only); int rend_service_load_keys(void); void rend_services_introduce(void); void rend_consider_services_upload(time_t now); diff --git a/src/or/rephist.c b/src/or/rephist.c index 7aa91b8f5..cd74f1b72 100644 --- a/src/or/rephist.c +++ b/src/or/rephist.c @@ -118,7 +118,7 @@ get_or_history(const char* id) { or_history_t *hist; - if (tor_mem_is_zero(id, DIGEST_LEN)) + if (tor_digest_is_zero(id)) return NULL; hist = digestmap_get(history_map, id); @@ -146,7 +146,7 @@ get_link_history(const char *from_id, const char *to_id) orhist = get_or_history(from_id); if (!orhist) return NULL; - if (tor_mem_is_zero(to_id, DIGEST_LEN)) + if (tor_digest_is_zero(to_id)) return NULL; lhist = (link_history_t*) digestmap_get(orhist->link_history_map, to_id); if (!lhist) { @@ -635,6 +635,7 @@ rep_hist_dump_stats(time_t now, int severity) digestmap_iter_t *orhist_it; const char *name1, *name2, *digest1, *digest2; char hexdigest1[HEX_DIGEST_LEN+1]; + char hexdigest2[HEX_DIGEST_LEN+1]; or_history_t *or_history; link_history_t *link_history; void *or_history_p, *link_history_p; @@ -695,7 +696,10 @@ rep_hist_dump_stats(time_t now, int severity) link_history = (link_history_t*) link_history_p; - ret = tor_snprintf(buffer+len, 2048-len, "%s(%ld/%ld); ", name2, + base16_encode(hexdigest2, sizeof(hexdigest2), digest2, DIGEST_LEN); + ret = tor_snprintf(buffer+len, 2048-len, "%s [%s](%ld/%ld); ", + name2, + hexdigest2, link_history->n_extend_ok, link_history->n_extend_ok+link_history->n_extend_fail); if (ret<0) @@ -1475,7 +1479,7 @@ rep_hist_fill_bandwidth_history(char *buf, size_t len, const bw_array_t *b) { char *cp = buf; int i, n; - or_options_t *options = get_options(); + const or_options_t *options = get_options(); uint64_t cutoff; if (b->num_maxes_set <= b->next_max_idx) { @@ -2293,7 +2297,7 @@ rep_hist_exit_stats_write(time_t now) /* Try to write to disk. */ statsdir = get_datadir_fname("stats"); - if (check_private_dir(statsdir, CPD_CREATE) < 0) { + if (check_private_dir(statsdir, CPD_CREATE, get_options()->User) < 0) { log_warn(LD_HIST, "Unable to create stats/ directory!"); goto done; } @@ -2387,8 +2391,7 @@ rep_hist_buffer_stats_add_circ(circuit_t *circ, time_t end_of_interval) stat = tor_malloc_zero(sizeof(circ_buffer_stats_t)); stat->processed_cells = orcirc->processed_cells; /* 1000.0 for s -> ms; 2.0 because of app-ward and exit-ward queues */ - stat->mean_num_cells_in_queue = interval_length == 0 ? 0.0 : - (double) orcirc->total_cell_waiting_time / + stat->mean_num_cells_in_queue = (double) orcirc->total_cell_waiting_time / (double) interval_length / 1000.0 / 2.0; stat->mean_time_cells_in_queue = (double) orcirc->total_cell_waiting_time / @@ -2438,8 +2441,8 @@ rep_hist_buffer_stats_write(time_t now) int processed_cells[SHARES], circs_in_share[SHARES], number_of_circuits, i; double queued_cells[SHARES], time_in_queue[SHARES]; - smartlist_t *str_build = smartlist_create(); - char *str = NULL, *buf=NULL; + smartlist_t *str_build = NULL; + char *str = NULL, *buf = NULL; circuit_t *circ; if (!start_of_buffer_stats_interval) @@ -2447,6 +2450,8 @@ rep_hist_buffer_stats_write(time_t now) if (start_of_buffer_stats_interval + WRITE_STATS_INTERVAL > now) goto done; /* Not ready to write */ + str_build = smartlist_create(); + /* add current circuits to stats */ for (circ = _circuit_get_global_list(); circ; circ = circ->next) rep_hist_buffer_stats_add_circ(circ, now); @@ -2482,7 +2487,7 @@ rep_hist_buffer_stats_write(time_t now) smartlist_clear(circuits_for_buffer_stats); /* write to file */ statsdir = get_datadir_fname("stats"); - if (check_private_dir(statsdir, CPD_CREATE) < 0) + if (check_private_dir(statsdir, CPD_CREATE, get_options()->User) < 0) goto done; filename = get_datadir_fname2("stats", "buffer-stats"); out = start_writing_to_stdio_file(filename, OPEN_FLAGS_APPEND, @@ -2753,7 +2758,7 @@ rep_hist_conn_stats_write(time_t now) /* Try to write to disk. */ statsdir = get_datadir_fname("stats"); - if (check_private_dir(statsdir, CPD_CREATE) < 0) { + if (check_private_dir(statsdir, CPD_CREATE, get_options()->User) < 0) { log_warn(LD_HIST, "Unable to create stats/ directory!"); goto done; } diff --git a/src/or/router.c b/src/or/router.c index 6de069f03..eaad57bb9 100644 --- a/src/or/router.c +++ b/src/or/router.c @@ -84,12 +84,16 @@ static authority_cert_t *legacy_key_certificate = NULL; static void set_onion_key(crypto_pk_env_t *k) { + if (onionkey && !crypto_pk_cmp_keys(onionkey, k)) { + /* k is already our onion key; free it and return */ + crypto_free_pk_env(k); + return; + } tor_mutex_acquire(key_lock); crypto_free_pk_env(onionkey); onionkey = k; - onionkey_set_at = time(NULL); tor_mutex_release(key_lock); - mark_my_descriptor_dirty(); + mark_my_descriptor_dirty("set onion key"); } /** Return the current onion key. Requires that the onion key has been @@ -276,7 +280,7 @@ rotate_onion_key(void) now = time(NULL); state->LastRotatedOnionKey = onionkey_set_at = now; tor_mutex_release(key_lock); - mark_my_descriptor_dirty(); + mark_my_descriptor_dirty("rotated onion key"); or_state_mark_dirty(state, get_options()->AvoidDiskWrites ? now+3600 : 0); goto done; error: @@ -493,10 +497,10 @@ init_keys(void) char fingerprint_line[MAX_NICKNAME_LEN+FINGERPRINT_LEN+3]; const char *mydesc; crypto_pk_env_t *prkey; - char digest[20]; - char v3_digest[20]; + char digest[DIGEST_LEN]; + char v3_digest[DIGEST_LEN]; char *cp; - or_options_t *options = get_options(); + const or_options_t *options = get_options(); dirinfo_type_t type; time_t now = time(NULL); trusted_dir_server_t *ds; @@ -506,7 +510,8 @@ init_keys(void) if (!key_lock) key_lock = tor_mutex_new(); - /* There are a couple of paths that put us here before */ + /* There are a couple of paths that put us here before we've asked + * openssl to initialize itself. */ if (crypto_global_init(get_options()->HardwareAccel, get_options()->AccelName, get_options()->AccelDir)) { @@ -535,12 +540,12 @@ init_keys(void) return 0; } /* Make sure DataDirectory exists, and is private. */ - if (check_private_dir(options->DataDirectory, CPD_CREATE)) { + if (check_private_dir(options->DataDirectory, CPD_CREATE, options->User)) { return -1; } /* Check the key directory. */ keydir = get_datadir_fname("keys"); - if (check_private_dir(keydir, CPD_CREATE)) { + if (check_private_dir(keydir, CPD_CREATE, options->User)) { tor_free(keydir); return -1; } @@ -707,8 +712,8 @@ init_keys(void) ds = router_get_trusteddirserver_by_digest(digest); if (!ds) { ds = add_trusted_dir_server(options->Nickname, NULL, - (uint16_t)options->DirPort, - (uint16_t)options->ORPort, + router_get_advertised_dir_port(options, 0), + router_get_advertised_or_port(options), digest, v3_digest, type); @@ -725,7 +730,7 @@ init_keys(void) ds->type = type; } if (v3_digest_set && (ds->type & V3_DIRINFO) && - memcmp(v3_digest, ds->v3_identity_digest, DIGEST_LEN)) { + tor_memneq(v3_digest, ds->v3_identity_digest, DIGEST_LEN)) { log_warn(LD_DIR, "V3 identity key does not match identity declared in " "DirServer line. Adjusting."); memcpy(ds->v3_identity_digest, v3_digest, DIGEST_LEN); @@ -763,7 +768,7 @@ router_reset_reachability(void) int check_whether_orport_reachable(void) { - or_options_t *options = get_options(); + const or_options_t *options = get_options(); return options->AssumeReachable || can_reach_or_port; } @@ -772,7 +777,7 @@ check_whether_orport_reachable(void) int check_whether_dirport_reachable(void) { - or_options_t *options = get_options(); + const or_options_t *options = get_options(); return !options->DirPort || options->AssumeReachable || we_are_hibernating() || @@ -787,7 +792,7 @@ check_whether_dirport_reachable(void) * a DirPort. */ static int -decide_to_advertise_dirport(or_options_t *options, uint16_t dir_port) +decide_to_advertise_dirport(const or_options_t *options, uint16_t dir_port) { static int advertising=1; /* start out assuming we will advertise */ int new_choice=1; @@ -805,6 +810,8 @@ decide_to_advertise_dirport(or_options_t *options, uint16_t dir_port) return 0; if (!check_whether_dirport_reachable()) return 0; + if (!router_get_advertised_dir_port(options, dir_port)) + return 0; /* Section two: reasons to publish or not publish that the user * might find surprising. These are generally config options that @@ -853,7 +860,7 @@ consider_testing_reachability(int test_or, int test_dir) const routerinfo_t *me = router_get_my_routerinfo(); int orport_reachable = check_whether_orport_reachable(); tor_addr_t addr; - or_options_t *options = get_options(); + const or_options_t *options = get_options(); if (!me) return; @@ -914,7 +921,7 @@ router_orport_found_reachable(void) get_options()->_PublishServerDescriptor != NO_DIRINFO ? " Publishing server descriptor." : ""); can_reach_or_port = 1; - mark_my_descriptor_dirty(); + mark_my_descriptor_dirty("ORPort found reachable"); control_event_server_status(LOG_NOTICE, "REACHABILITY_SUCCEEDED ORADDRESS=%s:%d", me->address, me->or_port); @@ -931,7 +938,7 @@ router_dirport_found_reachable(void) "from the outside. Excellent."); can_reach_dir_port = 1; if (decide_to_advertise_dirport(get_options(), me->dir_port)) - mark_my_descriptor_dirty(); + mark_my_descriptor_dirty("DirPort found reachable"); control_event_server_status(LOG_NOTICE, "REACHABILITY_SUCCEEDED DIRADDRESS=%s:%d", me->address, me->dir_port); @@ -971,7 +978,7 @@ router_perform_bandwidth_test(int num_circs, time_t now) * directory server. */ int -authdir_mode(or_options_t *options) +authdir_mode(const or_options_t *options) { return options->AuthoritativeDir != 0; } @@ -979,7 +986,7 @@ authdir_mode(or_options_t *options) * directory server. */ int -authdir_mode_v1(or_options_t *options) +authdir_mode_v1(const or_options_t *options) { return authdir_mode(options) && options->V1AuthoritativeDir != 0; } @@ -987,7 +994,7 @@ authdir_mode_v1(or_options_t *options) * directory server. */ int -authdir_mode_v2(or_options_t *options) +authdir_mode_v2(const or_options_t *options) { return authdir_mode(options) && options->V2AuthoritativeDir != 0; } @@ -995,13 +1002,13 @@ authdir_mode_v2(or_options_t *options) * directory server. */ int -authdir_mode_v3(or_options_t *options) +authdir_mode_v3(const or_options_t *options) { return authdir_mode(options) && options->V3AuthoritativeDir != 0; } /** Return true iff we are a v1, v2, or v3 directory authority. */ int -authdir_mode_any_main(or_options_t *options) +authdir_mode_any_main(const or_options_t *options) { return options->V1AuthoritativeDir || options->V2AuthoritativeDir || @@ -1010,7 +1017,7 @@ authdir_mode_any_main(or_options_t *options) /** Return true if we believe ourselves to be any kind of * authoritative directory beyond just a hidserv authority. */ int -authdir_mode_any_nonhidserv(or_options_t *options) +authdir_mode_any_nonhidserv(const or_options_t *options) { return options->BridgeAuthoritativeDir || authdir_mode_any_main(options); @@ -1019,7 +1026,7 @@ authdir_mode_any_nonhidserv(or_options_t *options) * authoritative about receiving and serving descriptors of type * <b>purpose</b> its dirport. Use -1 for "any purpose". */ int -authdir_mode_handles_descs(or_options_t *options, int purpose) +authdir_mode_handles_descs(const or_options_t *options, int purpose) { if (purpose < 0) return authdir_mode_any_nonhidserv(options); @@ -1034,7 +1041,7 @@ authdir_mode_handles_descs(or_options_t *options, int purpose) * publishes its own network statuses. */ int -authdir_mode_publishes_statuses(or_options_t *options) +authdir_mode_publishes_statuses(const or_options_t *options) { if (authdir_mode_bridge(options)) return 0; @@ -1044,7 +1051,7 @@ authdir_mode_publishes_statuses(or_options_t *options) * tests reachability of the descriptors it learns about. */ int -authdir_mode_tests_reachability(or_options_t *options) +authdir_mode_tests_reachability(const or_options_t *options) { return authdir_mode_handles_descs(options, -1); } @@ -1052,7 +1059,7 @@ authdir_mode_tests_reachability(or_options_t *options) * directory server. */ int -authdir_mode_bridge(or_options_t *options) +authdir_mode_bridge(const or_options_t *options) { return authdir_mode(options) && options->BridgeAuthoritativeDir != 0; } @@ -1060,7 +1067,7 @@ authdir_mode_bridge(or_options_t *options) /** Return true iff we are trying to be a server. */ int -server_mode(or_options_t *options) +server_mode(const or_options_t *options) { if (options->ClientOnly) return 0; return (options->ORPort != 0 || options->ORListenAddress); @@ -1069,7 +1076,7 @@ server_mode(or_options_t *options) /** Return true iff we are trying to be a non-bridge server. */ int -public_server_mode(or_options_t *options) +public_server_mode(const or_options_t *options) { if (!server_mode(options)) return 0; return (!options->BridgeRelay); @@ -1079,7 +1086,7 @@ public_server_mode(or_options_t *options) * in the consensus mean that we don't want to allow exits from circuits * we got from addresses not known to be servers. */ int -should_refuse_unknown_exits(or_options_t *options) +should_refuse_unknown_exits(const or_options_t *options) { if (options->RefuseUnknownExits != -1) { return options->RefuseUnknownExits; @@ -1111,7 +1118,7 @@ set_server_advertised(int s) /** Return true iff we are trying to be a socks proxy. */ int -proxy_mode(or_options_t *options) +proxy_mode(const or_options_t *options) { return (options->SocksPort != 0 || options->TransPort != 0 || @@ -1132,7 +1139,7 @@ proxy_mode(or_options_t *options) static int decide_if_publishable_server(void) { - or_options_t *options = get_options(); + const or_options_t *options = get_options(); if (options->ClientOnly) return 0; @@ -1142,6 +1149,8 @@ decide_if_publishable_server(void) return 0; if (authdir_mode(options)) return 1; + if (!router_get_advertised_or_port(options)) + return 0; return check_whether_orport_reachable(); } @@ -1171,6 +1180,40 @@ consider_publishable_server(int force) } } +/** Return the port that we should advertise as our ORPort; this is either + * the one configured in the ORPort option, or the one we actually bound to + * if ORPort is "auto". */ +uint16_t +router_get_advertised_or_port(const or_options_t *options) +{ + if (options->ORPort == CFG_AUTO_PORT) { + connection_t *c = connection_get_by_type(CONN_TYPE_OR_LISTENER); + if (c) + return c->port; + return 0; + } + return options->ORPort; +} + +/** Return the port that we should advertise as our DirPort; + * this is one of three possibilities: + * The one that is passed as <b>dirport</b> if the DirPort option is 0, or + * the one configured in the DirPort option, + * or the one we actually bound to if DirPort is "auto". */ +uint16_t +router_get_advertised_dir_port(const or_options_t *options, uint16_t dirport) +{ + if (!options->DirPort) + return dirport; + if (options->DirPort == CFG_AUTO_PORT) { + connection_t *c = connection_get_by_type(CONN_TYPE_DIR_LISTENER); + if (c) + return c->port; + return 0; + } + return options->DirPort; +} + /* * OR descriptor generation. */ @@ -1208,6 +1251,10 @@ router_upload_dir_desc_to_dirservers(int force) return; if (!force && !desc_needs_upload) return; + + log_info(LD_OR, "Uploading relay descriptor to directory authorities%s", + force ? " (forced)" : ""); + desc_needs_upload = 0; desc_len = ri->cache_info.signed_descriptor_len; @@ -1267,7 +1314,7 @@ int router_digest_is_me(const char *digest) { return (server_identitykey && - !memcmp(server_identitykey_digest, digest, DIGEST_LEN)); + tor_memeq(server_identitykey_digest, digest, DIGEST_LEN)); } /** Return true iff I'm a server and <b>digest</b> is equal to @@ -1279,7 +1326,7 @@ router_extrainfo_digest_is_me(const char *digest) if (!ei) return 0; - return !memcmp(digest, + return tor_memeq(digest, ei->cache_info.signed_descriptor_digest, DIGEST_LEN); } @@ -1355,7 +1402,7 @@ static int router_guess_address_from_dir_headers(uint32_t *guess); * dirserver headers. Place the answer in *<b>addr</b> and return * 0 on success, else return -1 if we have no guess. */ int -router_pick_published_address(or_options_t *options, uint32_t *addr) +router_pick_published_address(const or_options_t *options, uint32_t *addr) { if (resolve_my_address(LOG_INFO, options, addr, NULL) < 0) { log_info(LD_CONFIG, "Could not determine our address locally. " @@ -1382,12 +1429,13 @@ router_rebuild_descriptor(int force) uint32_t addr; char platform[256]; int hibernating = we_are_hibernating(); - or_options_t *options = get_options(); + const or_options_t *options = get_options(); if (desc_clean_since && !force) return 0; - if (router_pick_published_address(options, &addr) < 0) { + if (router_pick_published_address(options, &addr) < 0 || + router_get_advertised_or_port(options) == 0) { /* Stop trying to rebuild our descriptor every second. We'll * learn that it's time to try again when ip_address_changed() * marks it dirty. */ @@ -1395,13 +1443,15 @@ router_rebuild_descriptor(int force) return -1; } + log_info(LD_OR, "Rebuilding relay descriptor%s", force ? " (forced)" : ""); + ri = tor_malloc_zero(sizeof(routerinfo_t)); ri->cache_info.routerlist_index = -1; ri->address = tor_dup_ip(addr); ri->nickname = tor_strdup(options->Nickname); ri->addr = addr; - ri->or_port = options->ORPort; - ri->dir_port = options->DirPort; + ri->or_port = router_get_advertised_or_port(options); + ri->dir_port = router_get_advertised_dir_port(options, 0); ri->cache_info.published_on = time(NULL); ri->onion_pkey = crypto_pk_dup_key(get_onion_key()); /* must invoke from * main thread */ @@ -1567,14 +1617,15 @@ void mark_my_descriptor_dirty_if_older_than(time_t when) { if (desc_clean_since < when) - mark_my_descriptor_dirty(); + mark_my_descriptor_dirty("time for new descriptor"); } /** Call when the current descriptor is out of date. */ void -mark_my_descriptor_dirty(void) +mark_my_descriptor_dirty(const char *reason) { desc_clean_since = 0; + log_info(LD_OR, "Decided to publish new relay descriptor: %s", reason); } /** How frequently will we republish our descriptor because of large (factor @@ -1599,7 +1650,7 @@ check_descriptor_bandwidth_changed(time_t now) if (last_changed+MAX_BANDWIDTH_CHANGE_FREQ < now) { log_info(LD_GENERAL, "Measured bandwidth has changed; rebuilding descriptor."); - mark_my_descriptor_dirty(); + mark_my_descriptor_dirty("bandwidth has changed"); last_changed = now; } } @@ -1640,7 +1691,7 @@ void check_descriptor_ipaddress_changed(time_t now) { uint32_t prev, cur; - or_options_t *options = get_options(); + const or_options_t *options = get_options(); (void) now; if (!desc_routerinfo) @@ -1672,7 +1723,7 @@ router_new_address_suggestion(const char *suggestion, { uint32_t addr, cur = 0; struct in_addr in; - or_options_t *options = get_options(); + const or_options_t *options = get_options(); /* first, learn what the IP address actually is */ if (!tor_inet_aton(suggestion, &in)) { @@ -1771,7 +1822,7 @@ router_dump_router_to_string(char *s, size_t maxlen, routerinfo_t *router, int result=0; addr_policy_t *tmpe; char *family_line; - or_options_t *options = get_options(); + const or_options_t *options = get_options(); /* Make sure the identity key matches the one in the routerinfo. */ if (crypto_pk_cmp_keys(ident_key, router->identity_pkey)) { @@ -2013,7 +2064,7 @@ int extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo, crypto_pk_env_t *ident_key) { - or_options_t *options = get_options(); + const or_options_t *options = get_options(); char identity[HEX_DIGEST_LEN+1]; char published[ISO_TIME_LEN+1]; char digest[DIGEST_LEN]; @@ -2198,6 +2249,186 @@ is_legal_hexdigest(const char *s) strspn(s,HEX_CHARACTERS)==HEX_DIGEST_LEN); } +/** Use <b>buf</b> (which must be at least NODE_DESC_BUF_LEN bytes long) to + * hold a human-readable description of a node with identity digest + * <b>id_digest</b>, named-status <b>is_named</b>, nickname <b>nickname</b>, + * and address <b>addr</b> or <b>addr32h</b>. + * + * The <b>nickname</b> and <b>addr</b> fields are optional and may be set to + * NULL. The <b>addr32h</b> field is optional and may be set to 0. + * + * Return a pointer to the front of <b>buf</b>. + */ +const char * +format_node_description(char *buf, + const char *id_digest, + int is_named, + const char *nickname, + const tor_addr_t *addr, + uint32_t addr32h) +{ + char *cp; + + if (!buf) + return "<NULL BUFFER>"; + + buf[0] = '$'; + base16_encode(buf+1, HEX_DIGEST_LEN+1, id_digest, DIGEST_LEN); + cp = buf+1+HEX_DIGEST_LEN; + if (nickname) { + buf[1+HEX_DIGEST_LEN] = is_named ? '=' : '~'; + strlcpy(buf+1+HEX_DIGEST_LEN+1, nickname, MAX_NICKNAME_LEN+1); + cp += strlen(cp); + } + if (addr32h || addr) { + memcpy(cp, " at ", 4); + cp += 4; + if (addr) { + tor_addr_to_str(cp, addr, TOR_ADDR_BUF_LEN, 0); + } else { + struct in_addr in; + in.s_addr = htonl(addr32h); + tor_inet_ntoa(&in, cp, INET_NTOA_BUF_LEN); + } + } + return buf; +} + +/** Use <b>buf</b> (which must be at least NODE_DESC_BUF_LEN bytes long) to + * hold a human-readable description of <b>ri</b>. + * + * + * Return a pointer to the front of <b>buf</b>. + */ +const char * +router_get_description(char *buf, const routerinfo_t *ri) +{ + if (!ri) + return "<null>"; + return format_node_description(buf, + ri->cache_info.identity_digest, + router_is_named(ri), + ri->nickname, + NULL, + ri->addr); +} + +/** Use <b>buf</b> (which must be at least NODE_DESC_BUF_LEN bytes long) to + * hold a human-readable description of <b>node</b>. + * + * Return a pointer to the front of <b>buf</b>. + */ +const char * +node_get_description(char *buf, const node_t *node) +{ + const char *nickname = NULL; + uint32_t addr32h = 0; + int is_named = 0; + + if (!node) + return "<null>"; + + if (node->rs) { + nickname = node->rs->nickname; + is_named = node->rs->is_named; + addr32h = node->rs->addr; + } else if (node->ri) { + nickname = node->ri->nickname; + addr32h = node->ri->addr; + } + + return format_node_description(buf, + node->identity, + is_named, + nickname, + NULL, + addr32h); +} + +/** Use <b>buf</b> (which must be at least NODE_DESC_BUF_LEN bytes long) to + * hold a human-readable description of <b>rs</b>. + * + * Return a pointer to the front of <b>buf</b>. + */ +const char * +routerstatus_get_description(char *buf, const routerstatus_t *rs) +{ + if (!rs) + return "<null>"; + return format_node_description(buf, + rs->identity_digest, + rs->is_named, + rs->nickname, + NULL, + rs->addr); +} + +/** Use <b>buf</b> (which must be at least NODE_DESC_BUF_LEN bytes long) to + * hold a human-readable description of <b>ei</b>. + * + * Return a pointer to the front of <b>buf</b>. + */ +const char * +extend_info_get_description(char *buf, const extend_info_t *ei) +{ + if (!ei) + return "<null>"; + return format_node_description(buf, + ei->identity_digest, + 0, + ei->nickname, + &ei->addr, + 0); +} + +/** Return a human-readable description of the routerinfo_t <b>ri</b>. + * + * This function is not thread-safe. Each call to this function invalidates + * previous values returned by this function. + */ +const char * +router_describe(const routerinfo_t *ri) +{ + static char buf[NODE_DESC_BUF_LEN]; + return router_get_description(buf, ri); +} + +/** Return a human-readable description of the node_t <b>node</b>. + * + * This function is not thread-safe. Each call to this function invalidates + * previous values returned by this function. + */ +const char * +node_describe(const node_t *node) +{ + static char buf[NODE_DESC_BUF_LEN]; + return node_get_description(buf, node); +} + +/** Return a human-readable description of the routerstatus_t <b>rs</b>. + * + * This function is not thread-safe. Each call to this function invalidates + * previous values returned by this function. + */ +const char * +routerstatus_describe(const routerstatus_t *rs) +{ + static char buf[NODE_DESC_BUF_LEN]; + return routerstatus_get_description(buf, rs); +} + +/** Return a human-readable description of the extend_info_t <b>ri</b>. + * + * This function is not thread-safe. Each call to this function invalidates + * previous values returned by this function. + */ +const char * +extend_info_describe(const extend_info_t *ei) +{ + static char buf[NODE_DESC_BUF_LEN]; + return extend_info_get_description(buf, ei); +} + /** Set <b>buf</b> (which must have MAX_VERBOSE_NICKNAME_LEN+1 bytes) to the * verbose representation of the identity of <b>router</b>. The format is: * A dollar sign. @@ -2210,7 +2441,7 @@ router_get_verbose_nickname(char *buf, const routerinfo_t *router) { const char *good_digest = networkstatus_get_router_digest_by_nickname( router->nickname); - int is_named = good_digest && !memcmp(good_digest, + int is_named = good_digest && tor_memeq(good_digest, router->cache_info.identity_digest, DIGEST_LEN); buf[0] = '$'; diff --git a/src/or/router.h b/src/or/router.h index e58b1ed53..f6d3c1233 100644 --- a/src/or/router.h +++ b/src/or/router.h @@ -39,27 +39,31 @@ void router_orport_found_reachable(void); void router_dirport_found_reachable(void); void router_perform_bandwidth_test(int num_circs, time_t now); -int authdir_mode(or_options_t *options); -int authdir_mode_v1(or_options_t *options); -int authdir_mode_v2(or_options_t *options); -int authdir_mode_v3(or_options_t *options); -int authdir_mode_any_main(or_options_t *options); -int authdir_mode_any_nonhidserv(or_options_t *options); -int authdir_mode_handles_descs(or_options_t *options, int purpose); -int authdir_mode_publishes_statuses(or_options_t *options); -int authdir_mode_tests_reachability(or_options_t *options); -int authdir_mode_bridge(or_options_t *options); +int authdir_mode(const or_options_t *options); +int authdir_mode_v1(const or_options_t *options); +int authdir_mode_v2(const or_options_t *options); +int authdir_mode_v3(const or_options_t *options); +int authdir_mode_any_main(const or_options_t *options); +int authdir_mode_any_nonhidserv(const or_options_t *options); +int authdir_mode_handles_descs(const or_options_t *options, int purpose); +int authdir_mode_publishes_statuses(const or_options_t *options); +int authdir_mode_tests_reachability(const or_options_t *options); +int authdir_mode_bridge(const or_options_t *options); -int server_mode(or_options_t *options); -int public_server_mode(or_options_t *options); +uint16_t router_get_advertised_or_port(const or_options_t *options); +uint16_t router_get_advertised_dir_port(const or_options_t *options, + uint16_t dirport); + +int server_mode(const or_options_t *options); +int public_server_mode(const or_options_t *options); int advertised_server_mode(void); -int proxy_mode(or_options_t *options); +int proxy_mode(const or_options_t *options); void consider_publishable_server(int force); -int should_refuse_unknown_exits(or_options_t *options); +int should_refuse_unknown_exits(const or_options_t *options); void router_upload_dir_desc_to_dirservers(int force); void mark_my_descriptor_dirty_if_older_than(time_t when); -void mark_my_descriptor_dirty(void); +void mark_my_descriptor_dirty(const char *reason); void check_descriptor_bandwidth_changed(time_t now); void check_descriptor_ipaddress_changed(time_t now); void router_new_address_suggestion(const char *suggestion, @@ -73,7 +77,7 @@ int router_digest_is_me(const char *digest); int router_extrainfo_digest_is_me(const char *digest); int router_is_me(const routerinfo_t *router); int router_fingerprint_is_me(const char *fp); -int router_pick_published_address(or_options_t *options, uint32_t *addr); +int router_pick_published_address(const or_options_t *options, uint32_t *addr); int router_rebuild_descriptor(int force); int router_dump_router_to_string(char *s, size_t maxlen, routerinfo_t *router, crypto_pk_env_t *ident_key); @@ -82,6 +86,30 @@ int extrainfo_dump_to_string(char **s, extrainfo_t *extrainfo, int is_legal_nickname(const char *s); int is_legal_nickname_or_hexdigest(const char *s); int is_legal_hexdigest(const char *s); + +/** + * Longest allowed output of format_node_description, plus 1 character for + * NUL. This allows space for: + * "$FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF~xxxxxxxxxxxxxxxxxxx at" + * " [ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255]" + * plus a terminating NUL. + */ +#define NODE_DESC_BUF_LEN (MAX_VERBOSE_NICKNAME_LEN+4+TOR_ADDR_BUF_LEN) +const char *format_node_description(char *buf, + const char *id_digest, + int is_named, + const char *nickname, + const tor_addr_t *addr, + uint32_t addr32h); +const char *router_get_description(char *buf, const routerinfo_t *ri); +const char *node_get_description(char *buf, const node_t *node); +const char *routerstatus_get_description(char *buf, const routerstatus_t *rs); +const char *extend_info_get_description(char *buf, const extend_info_t *ei); +const char *router_describe(const routerinfo_t *ri); +const char *node_describe(const node_t *node); +const char *routerstatus_describe(const routerstatus_t *ri); +const char *extend_info_describe(const extend_info_t *ei); + void router_get_verbose_nickname(char *buf, const routerinfo_t *router); void routerstatus_get_verbose_nickname(char *buf, const routerstatus_t *router); diff --git a/src/or/routerlist.c b/src/or/routerlist.c index 04f421481..15f643cf7 100644 --- a/src/or/routerlist.c +++ b/src/or/routerlist.c @@ -57,7 +57,7 @@ static const char *signed_descriptor_get_body_impl( static void list_pending_downloads(digestmap_t *result, int purpose, const char *prefix); static void launch_dummy_descriptor_download_as_needed(time_t now, - or_options_t *options); + const or_options_t *options); DECLARE_TYPED_DIGESTMAP_FNS(sdmap_, digest_sd_map_t, signed_descriptor_t) DECLARE_TYPED_DIGESTMAP_FNS(rimap_, digest_ri_map_t, routerinfo_t) @@ -170,7 +170,7 @@ already_have_cert(authority_cert_t *cert) SMARTLIST_FOREACH(cl->certs, authority_cert_t *, c, { - if (!memcmp(c->cache_info.signed_descriptor_digest, + if (tor_memeq(c->cache_info.signed_descriptor_digest, cert->cache_info.signed_descriptor_digest, DIGEST_LEN)) return 1; @@ -384,16 +384,16 @@ authority_cert_get_by_sk_digest(const char *sk_digest) return NULL; if ((c = get_my_v3_authority_cert()) && - !memcmp(c->signing_key_digest, sk_digest, DIGEST_LEN)) + tor_memeq(c->signing_key_digest, sk_digest, DIGEST_LEN)) return c; if ((c = get_my_v3_legacy_cert()) && - !memcmp(c->signing_key_digest, sk_digest, DIGEST_LEN)) + tor_memeq(c->signing_key_digest, sk_digest, DIGEST_LEN)) return c; DIGESTMAP_FOREACH(trusted_dir_certs, key, cert_list_t *, cl) { SMARTLIST_FOREACH(cl->certs, authority_cert_t *, cert, { - if (!memcmp(cert->signing_key_digest, sk_digest, DIGEST_LEN)) + if (tor_memeq(cert->signing_key_digest, sk_digest, DIGEST_LEN)) return cert; }); } DIGESTMAP_FOREACH_END; @@ -412,7 +412,7 @@ authority_cert_get_by_digests(const char *id_digest, !(cl = digestmap_get(trusted_dir_certs, id_digest))) return NULL; SMARTLIST_FOREACH(cl->certs, authority_cert_t *, cert, - if (!memcmp(cert->signing_key_digest, sk_digest, DIGEST_LEN)) + if (tor_memeq(cert->signing_key_digest, sk_digest, DIGEST_LEN)) return cert; ); return NULL; @@ -1008,7 +1008,7 @@ router_get_trusteddirserver_by_digest(const char *digest) SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, ds, { - if (!memcmp(ds->digest, digest, DIGEST_LEN)) + if (tor_memeq(ds->digest, digest, DIGEST_LEN)) return ds; }); @@ -1027,7 +1027,7 @@ trusteddirserver_get_by_v3_auth_digest(const char *digest) SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, ds, { - if (!memcmp(ds->v3_identity_digest, digest, DIGEST_LEN) && + if (tor_memeq(ds->v3_identity_digest, digest, DIGEST_LEN) && (ds->type & V3_DIRINFO)) return ds; }); @@ -1077,7 +1077,7 @@ router_pick_trusteddirserver(dirinfo_type_t type, int flags) static const routerstatus_t * router_pick_directory_server_impl(dirinfo_type_t type, int flags) { - or_options_t *options = get_options(); + const or_options_t *options = get_options(); const node_t *result; smartlist_t *direct, *tunnel; smartlist_t *trusted_direct, *trusted_tunnel; @@ -1200,7 +1200,7 @@ static const routerstatus_t * router_pick_trusteddirserver_impl(dirinfo_type_t type, int flags, int *n_busy_out) { - or_options_t *options = get_options(); + const or_options_t *options = get_options(); smartlist_t *direct, *tunnel; smartlist_t *overloaded_direct, *overloaded_tunnel; const routerinfo_t *me = router_get_my_routerinfo(); @@ -1367,7 +1367,7 @@ nodelist_add_node_family(smartlist_t *sl, const node_t *node) /* XXXX MOVE */ const smartlist_t *all_nodes = nodelist_get_list(); const smartlist_t *declared_family; - or_options_t *options = get_options(); + const or_options_t *options = get_options(); tor_assert(node); @@ -1456,7 +1456,7 @@ int nodes_in_same_family(const node_t *node1, const node_t *node2) { /* XXXX MOVE */ - or_options_t *options = get_options(); + const or_options_t *options = get_options(); /* Are they in the same family because of their addresses? */ if (options->EnforceDistinctSubnets) { @@ -1565,7 +1565,7 @@ router_find_exact_exit_enclave(const char *address, uint16_t port) uint32_t addr; struct in_addr in; tor_addr_t a; - or_options_t *options = get_options(); + const or_options_t *options = get_options(); if (!tor_inet_aton(address, &in)) return NULL; /* it's not an IP already */ @@ -2274,25 +2274,27 @@ hex_digest_nickname_matches(const char *hexdigest, const char *identity_digest, return 0; if (nn_char == '=' || nn_char == '~') { + if (!nickname) + return 0; if (strcasecmp(nn_buf, nickname)) return 0; if (nn_char == '=' && !is_named) return 0; } - return !memcmp(digest, identity_digest, DIGEST_LEN); + return tor_memeq(digest, identity_digest, DIGEST_LEN); } /* Return true iff <b>router</b> is listed as named in the current * consensus. */ -static int +int router_is_named(const routerinfo_t *router) { const char *digest = networkstatus_get_router_digest_by_nickname(router->nickname); return (digest && - !memcmp(digest, router->cache_info.identity_digest, DIGEST_LEN)); + tor_memeq(digest, router->cache_info.identity_digest, DIGEST_LEN)); } /** Return true iff the digest of <b>router</b>'s identity key, @@ -2382,8 +2384,8 @@ router_get_by_nickname(const char *nickname, int warn_if_unnamed) if (n_matches <= 1 || router->is_running) best_match = router; } else if (maybedigest && - !memcmp(digest, router->cache_info.identity_digest, DIGEST_LEN) - ) { + tor_memeq(digest, router->cache_info.identity_digest, + DIGEST_LEN)) { if (router_hex_digest_matches(router, nickname)) return router; /* If we reach this point, we have a ID=name syntax that matches the @@ -2459,7 +2461,7 @@ router_digest_is_trusted_dir_type(const char *digest, dirinfo_type_t type) if (authdir_mode(get_options()) && router_digest_is_me(digest)) return 1; SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, ent, - if (!memcmp(digest, ent->digest, DIGEST_LEN)) { + if (tor_memeq(digest, ent->digest, DIGEST_LEN)) { return (!type) || ((type & ent->type) != 0); }); return 0; @@ -2608,7 +2610,7 @@ signed_descriptor_get_body_impl(const signed_descriptor_t *desc, tor_assert(r); if (!with_annotations) { - if (memcmp("router ", r, 7) && memcmp("extra-info ", r, 11)) { + if (fast_memcmp("router ", r, 7) && fast_memcmp("extra-info ", r, 11)) { char *cp = tor_strndup(r, 64); log_err(LD_DIR, "descriptor at %p begins with unexpected string %s. " "Is another process running in our data directory? Exiting.", @@ -3086,7 +3088,7 @@ routerlist_replace(routerlist_t *rl, routerinfo_t *ri_old, routerlist_insert(rl, ri_new); return; } - if (memcmp(ri_old->cache_info.identity_digest, + if (tor_memneq(ri_old->cache_info.identity_digest, ri_new->cache_info.identity_digest, DIGEST_LEN)) { /* digests don't match; digestmap_set won't replace */ rimap_remove(rl->identity_map, ri_old->cache_info.identity_digest); @@ -3103,7 +3105,7 @@ routerlist_replace(routerlist_t *rl, routerinfo_t *ri_old, &ri_new->cache_info); } - same_descriptors = ! memcmp(ri_old->cache_info.signed_descriptor_digest, + same_descriptors = tor_memeq(ri_old->cache_info.signed_descriptor_digest, ri_new->cache_info.signed_descriptor_digest, DIGEST_LEN); @@ -3125,7 +3127,7 @@ routerlist_replace(routerlist_t *rl, routerinfo_t *ri_old, sdmap_remove(rl->desc_digest_map, ri_old->cache_info.signed_descriptor_digest); - if (memcmp(ri_old->cache_info.extra_info_digest, + if (tor_memneq(ri_old->cache_info.extra_info_digest, ri_new->cache_info.extra_info_digest, DIGEST_LEN)) { ei_tmp = eimap_remove(rl->extra_info_map, ri_old->cache_info.extra_info_digest); @@ -3224,16 +3226,14 @@ router_set_status(const char *digest, int up) tor_assert(digest); SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, d, - if (!memcmp(d->digest, digest, DIGEST_LEN)) + if (tor_memeq(d->digest, digest, DIGEST_LEN)) d->is_running = up); node = node_get_mutable_by_id(digest); if (node) { #if 0 - char buf[MAX_VERBOSE_NICKNAME_LEN+1]; - node_get_verbose_nickname(node,buf); log_debug(LD_DIR,"Marking router %s as %s.", - buf, up ? "up" : "down"); + node_describe(node), up ? "up" : "down"); #endif if (!up && node_is_me(node) && !we_are_hibernating()) log_warn(LD_NET, "We just marked ourself as down. Are your external " @@ -3269,7 +3269,7 @@ router_add_to_routerlist(routerinfo_t *router, const char **msg, int from_cache, int from_fetch) { const char *id_digest; - or_options_t *options = get_options(); + const or_options_t *options = get_options(); int authdir = authdir_mode_handles_descs(options, router->purpose); int authdir_believes_valid = 0; routerinfo_t *old_router; @@ -3302,11 +3302,12 @@ router_add_to_routerlist(routerinfo_t *router, const char **msg, router->purpose == ROUTER_PURPOSE_BRIDGE && !was_bridge) { log_info(LD_DIR, "Replacing non-bridge descriptor with bridge " - "descriptor for router '%s'", router->nickname); + "descriptor for router %s", + router_describe(router)); } else { log_info(LD_DIR, - "Dropping descriptor that we already have for router '%s'", - router->nickname); + "Dropping descriptor that we already have for router %s", + router_describe(router)); *msg = "Router descriptor was not new."; routerinfo_free(router); return ROUTER_WAS_NOT_NEW; @@ -3330,8 +3331,8 @@ router_add_to_routerlist(routerinfo_t *router, const char **msg, /* We asked for it, so some networkstatus must have listed it when we * did. Save it if we're a cache in case somebody else asks for it. */ log_info(LD_DIR, - "Received a no-longer-recognized descriptor for router '%s'", - router->nickname); + "Received a no-longer-recognized descriptor for router %s", + router_describe(router)); *msg = "Router descriptor is not referenced by any network-status."; /* Only journal this desc if we'll be serving it. */ @@ -3348,7 +3349,7 @@ router_add_to_routerlist(routerinfo_t *router, const char **msg, { routerstatus_t *rs = networkstatus_v2_find_mutable_entry(ns, id_digest); - if (rs && !memcmp(rs->descriptor_digest, + if (rs && tor_memeq(rs->descriptor_digest, router->cache_info.signed_descriptor_digest, DIGEST_LEN)) rs->need_to_mirror = 0; @@ -3356,7 +3357,7 @@ router_add_to_routerlist(routerinfo_t *router, const char **msg, if (consensus) { routerstatus_t *rs = networkstatus_vote_find_mutable_entry( consensus, id_digest); - if (rs && !memcmp(rs->descriptor_digest, + if (rs && tor_memeq(rs->descriptor_digest, router->cache_info.signed_descriptor_digest, DIGEST_LEN)) { in_consensus = 1; @@ -3383,8 +3384,9 @@ router_add_to_routerlist(routerinfo_t *router, const char **msg, if (router->purpose == ROUTER_PURPOSE_BRIDGE && from_cache && !authdir_mode_bridge(options) && !routerinfo_is_a_configured_bridge(router)) { - log_info(LD_DIR, "Dropping bridge descriptor for '%s' because we have " - "no bridge configured at that address.", router->nickname); + log_info(LD_DIR, "Dropping bridge descriptor for %s because we have " + "no bridge configured at that address.", + safe_str_client(router_describe(router))); *msg = "Router descriptor was not a configured bridge."; routerinfo_free(router); return ROUTER_WAS_NOT_WANTED; @@ -3395,8 +3397,8 @@ router_add_to_routerlist(routerinfo_t *router, const char **msg, if (!in_consensus && (router->cache_info.published_on <= old_router->cache_info.published_on)) { /* Same key, but old. This one is not listed in the consensus. */ - log_debug(LD_DIR, "Not-new descriptor for router '%s'", - router->nickname); + log_debug(LD_DIR, "Not-new descriptor for router %s", + router_describe(router)); /* Only journal this desc if we'll be serving it. */ if (!from_cache && should_cache_old_descriptors()) signed_desc_append_to_journal(&router->cache_info, @@ -3406,9 +3408,8 @@ router_add_to_routerlist(routerinfo_t *router, const char **msg, return ROUTER_WAS_NOT_NEW; } else { /* Same key, and either new, or listed in the consensus. */ - log_debug(LD_DIR, "Replacing entry for router '%s/%s' [%s]", - router->nickname, old_router->nickname, - hex_str(id_digest,DIGEST_LEN)); + log_debug(LD_DIR, "Replacing entry for router %s", + router_describe(router)); if (routers_have_same_or_addr(router, old_router)) { /* these carry over when the address and orport are unchanged. */ router->last_reachable = old_router->last_reachable; @@ -3478,7 +3479,7 @@ _compare_old_routers_by_identity(const void **_a, const void **_b) { int i; const signed_descriptor_t *r1 = *_a, *r2 = *_b; - if ((i = memcmp(r1->identity_digest, r2->identity_digest, DIGEST_LEN))) + if ((i = fast_memcmp(r1->identity_digest, r2->identity_digest, DIGEST_LEN))) return i; return (int)(r1->published_on - r2->published_on); } @@ -3526,7 +3527,7 @@ routerlist_remove_old_cached_routers_with_id(time_t now, ident = ((signed_descriptor_t*)smartlist_get(lst, lo))->identity_digest; for (i = lo+1; i <= hi; ++i) { signed_descriptor_t *r = smartlist_get(lst, i); - tor_assert(!memcmp(ident, r->identity_digest, DIGEST_LEN)); + tor_assert(tor_memeq(ident, r->identity_digest, DIGEST_LEN)); } #endif /* Check whether we need to do anything at all. */ @@ -3684,8 +3685,8 @@ routerlist_remove_old_routers(void) /* Too old: remove it. (If we're a cache, just move it into * old_routers.) */ log_info(LD_DIR, - "Forgetting obsolete (too old) routerinfo for router '%s'", - router->nickname); + "Forgetting obsolete (too old) routerinfo for router %s", + router_describe(router)); routerlist_remove(routerlist, router, 1, now); i--; } @@ -3738,7 +3739,7 @@ routerlist_remove_old_routers(void) cur_id = r->identity_digest; hi = i; } - if (memcmp(cur_id, r->identity_digest, DIGEST_LEN)) { + if (tor_memneq(cur_id, r->identity_digest, DIGEST_LEN)) { routerlist_remove_old_cached_routers_with_id(now, cutoff, i+1, hi, retain); cur_id = r->identity_digest; @@ -3976,7 +3977,7 @@ signed_desc_digest_is_recognized(signed_descriptor_t *desc) if (consensus) { rs = networkstatus_vote_find_entry(consensus, desc->identity_digest); - if (rs && !memcmp(rs->descriptor_digest, + if (rs && tor_memeq(rs->descriptor_digest, desc->signed_descriptor_digest, DIGEST_LEN)) return 1; } @@ -3985,7 +3986,7 @@ signed_desc_digest_is_recognized(signed_descriptor_t *desc) { if (!(rs = networkstatus_v2_find_entry(ns, desc->identity_digest))) continue; - if (!memcmp(rs->descriptor_digest, + if (tor_memeq(rs->descriptor_digest, desc->signed_descriptor_digest, DIGEST_LEN)) return 1; }); @@ -4295,7 +4296,8 @@ initiate_descriptor_downloads(const routerstatus_t *source, * running, or otherwise not a descriptor that we would make any * use of even if we had it. Else return 1. */ static INLINE int -client_would_use_router(routerstatus_t *rs, time_t now, or_options_t *options) +client_would_use_router(const routerstatus_t *rs, time_t now, + const or_options_t *options) { if (!rs->is_flagged_running && !options->FetchUselessDescriptors) { /* If we had this router descriptor, we wouldn't even bother using it. @@ -4348,7 +4350,7 @@ launch_descriptor_downloads(int purpose, const routerstatus_t *source, time_t now) { int should_delay = 0, n_downloadable; - or_options_t *options = get_options(); + const or_options_t *options = get_options(); const char *descname; tor_assert(purpose == DIR_PURPOSE_FETCH_SERVERDESC || @@ -4452,7 +4454,7 @@ update_router_descriptor_cache_downloads_v2(time_t now) digestmap_t *map; /* Which descs are in progress, or assigned? */ int i, j, n; int n_download; - or_options_t *options = get_options(); + const or_options_t *options = get_options(); const smartlist_t *networkstatus_v2_list = networkstatus_get_v2_list(); if (! directory_fetches_dir_info_early(options)) { @@ -4594,7 +4596,7 @@ void update_consensus_router_descriptor_downloads(time_t now, int is_vote, networkstatus_t *consensus) { - or_options_t *options = get_options(); + const or_options_t *options = get_options(); digestmap_t *map = NULL; smartlist_t *no_longer_old = smartlist_create(); smartlist_t *downloadable = smartlist_create(); @@ -4630,7 +4632,7 @@ update_consensus_router_descriptor_downloads(time_t now, int is_vote, const routerinfo_t *ri; ++n_have; if (!(ri = router_get_by_id_digest(rs->identity_digest)) || - memcmp(ri->cache_info.signed_descriptor_digest, + tor_memneq(ri->cache_info.signed_descriptor_digest, sd->signed_descriptor_digest, DIGEST_LEN)) { /* We have a descriptor with this digest, but either there is no * entry in routerlist with the same ID (!ri), or there is one, @@ -4668,7 +4670,8 @@ update_consensus_router_descriptor_downloads(time_t now, int is_vote, if (oldrouter) format_iso_time(time_bufold, oldrouter->cache_info.published_on); log_info(LD_DIR, "Learned about %s (%s vs %s) from %s's vote (%s)", - rs->nickname, time_bufnew, + routerstatus_describe(rs), + time_bufnew, oldrouter ? time_bufold : "none", source->nickname, oldrouter ? "known" : "unknown"); } @@ -4723,7 +4726,8 @@ update_consensus_router_descriptor_downloads(time_t now, int is_vote, /** As needed, launch a dummy router descriptor fetch to see if our * address has changed. */ static void -launch_dummy_descriptor_download_as_needed(time_t now, or_options_t *options) +launch_dummy_descriptor_download_as_needed(time_t now, + const or_options_t *options) { static time_t last_dummy_download = 0; /* XXXX023 we could be smarter here; see notes on bug 652. */ @@ -4745,7 +4749,7 @@ launch_dummy_descriptor_download_as_needed(time_t now, or_options_t *options) void update_router_descriptor_downloads(time_t now) { - or_options_t *options = get_options(); + const or_options_t *options = get_options(); if (should_delay_dir_fetches(options)) return; if (!we_fetch_router_descriptors(options)) @@ -4762,7 +4766,7 @@ update_router_descriptor_downloads(time_t now) void update_extrainfo_downloads(time_t now) { - or_options_t *options = get_options(); + const or_options_t *options = get_options(); routerlist_t *rl; smartlist_t *wanted; digestmap_t *pending; @@ -4884,7 +4888,7 @@ get_dir_info_status_string(void) static void count_usable_descriptors(int *num_present, int *num_usable, const networkstatus_t *consensus, - or_options_t *options, time_t now, + const or_options_t *options, time_t now, routerset_t *in_set) { const int md = (consensus->flavor == FLAV_MICRODESC); @@ -4950,7 +4954,7 @@ update_router_have_minimum_dir_info(void) int num_present = 0, num_usable=0; time_t now = time(NULL); int res; - or_options_t *options = get_options(); + const or_options_t *options = get_options(); const networkstatus_t *consensus = networkstatus_get_reasonably_live_consensus(now,usable_consensus_flavor()); @@ -5159,13 +5163,14 @@ routerinfo_incompatible_with_extrainfo(const routerinfo_t *ri, return 1; } - digest_matches = !memcmp(ei->cache_info.signed_descriptor_digest, + digest_matches = tor_memeq(ei->cache_info.signed_descriptor_digest, sd->extra_info_digest, DIGEST_LEN); /* The identity must match exactly to have been generated at the same time * by the same router. */ - if (memcmp(ri->cache_info.identity_digest, ei->cache_info.identity_digest, - DIGEST_LEN)) { + if (tor_memneq(ri->cache_info.identity_digest, + ei->cache_info.identity_digest, + DIGEST_LEN)) { if (msg) *msg = "Extrainfo nickname or identity did not match routerinfo"; goto err; /* different servers */ } @@ -5175,7 +5180,7 @@ routerinfo_incompatible_with_extrainfo(const routerinfo_t *ri, if (crypto_pk_public_checksig(ri->identity_pkey, signed_digest, sizeof(signed_digest), ei->pending_sig, ei->pending_sig_len) != DIGEST_LEN || - memcmp(signed_digest, ei->cache_info.signed_descriptor_digest, + tor_memneq(signed_digest, ei->cache_info.signed_descriptor_digest, DIGEST_LEN)) { ei->bad_sig = 1; tor_free(ei->pending_sig); @@ -5271,25 +5276,25 @@ routerlist_assert_ok(const routerlist_t *rl) }); RIMAP_FOREACH(rl->identity_map, d, r) { - tor_assert(!memcmp(r->cache_info.identity_digest, d, DIGEST_LEN)); + tor_assert(tor_memeq(r->cache_info.identity_digest, d, DIGEST_LEN)); } DIGESTMAP_FOREACH_END; SDMAP_FOREACH(rl->desc_digest_map, d, sd) { - tor_assert(!memcmp(sd->signed_descriptor_digest, d, DIGEST_LEN)); + tor_assert(tor_memeq(sd->signed_descriptor_digest, d, DIGEST_LEN)); } DIGESTMAP_FOREACH_END; SDMAP_FOREACH(rl->desc_by_eid_map, d, sd) { tor_assert(!tor_digest_is_zero(d)); tor_assert(sd); - tor_assert(!memcmp(sd->extra_info_digest, d, DIGEST_LEN)); + tor_assert(tor_memeq(sd->extra_info_digest, d, DIGEST_LEN)); } DIGESTMAP_FOREACH_END; EIMAP_FOREACH(rl->extra_info_map, d, ei) { signed_descriptor_t *sd; - tor_assert(!memcmp(ei->cache_info.signed_descriptor_digest, + tor_assert(tor_memeq(ei->cache_info.signed_descriptor_digest, d, DIGEST_LEN)); sd = sdmap_get(rl->desc_by_eid_map, ei->cache_info.signed_descriptor_digest); // tor_assert(sd); // XXXX see above if (sd) { - tor_assert(!memcmp(ei->cache_info.signed_descriptor_digest, + tor_assert(tor_memeq(ei->cache_info.signed_descriptor_digest, sd->extra_info_digest, DIGEST_LEN)); } } DIGESTMAP_FOREACH_END; @@ -5335,7 +5340,7 @@ static int _compare_routerinfo_by_id_digest(const void **a, const void **b) { routerinfo_t *first = *(routerinfo_t **)a, *second = *(routerinfo_t **)b; - return memcmp(first->cache_info.identity_digest, + return fast_memcmp(first->cache_info.identity_digest, second->cache_info.identity_digest, DIGEST_LEN); } @@ -5496,7 +5501,7 @@ routerset_parse(routerset_t *target, const char *s, const char *description) void refresh_all_country_info(void) { - or_options_t *options = get_options(); + const or_options_t *options = get_options(); if (options->EntryNodes) routerset_refresh_countries(options->EntryNodes); @@ -5843,8 +5848,6 @@ int hid_serv_acting_as_directory(void) { const routerinfo_t *me = router_get_my_routerinfo(); - networkstatus_t *c; - const routerstatus_t *rs; if (!me) return 0; if (!get_options()->HidServDirectoryV2) { @@ -5852,22 +5855,6 @@ hid_serv_acting_as_directory(void) "because we have not been configured as such."); return 0; } - if (!(c = networkstatus_get_latest_consensus())) { - log_info(LD_REND, "There's no consensus, so I can't tell if I'm a hidden " - "service directory"); - return 0; - } - rs = networkstatus_vote_find_entry(c, me->cache_info.identity_digest); - if (!rs) { - log_info(LD_REND, "We're not listed in the consensus, so we're not " - "being a hidden service directory."); - return 0; - } - if (!rs->is_hs_dir) { - log_info(LD_REND, "We're not listed as a hidden service directory in " - "the consensus, so we won't be one."); - return 0; - } return 1; } diff --git a/src/or/routerlist.h b/src/or/routerlist.h index a613c34b8..3a8af6fd9 100644 --- a/src/or/routerlist.h +++ b/src/or/routerlist.h @@ -56,6 +56,7 @@ const node_t *router_choose_random_node(smartlist_t *excludedsmartlist, const routerinfo_t *router_get_by_nickname(const char *nickname, int warn_if_unnamed); +int router_is_named(const routerinfo_t *router); int router_digest_is_trusted_dir_type(const char *digest, dirinfo_type_t type); #define router_digest_is_trusted_dir(d) \ diff --git a/src/or/routerparse.c b/src/or/routerparse.c index 0410e5e37..d1b2cd0fb 100644 --- a/src/or/routerparse.c +++ b/src/or/routerparse.c @@ -1093,7 +1093,7 @@ check_signature_token(const char *digest, } // log_debug(LD_DIR,"Signed %s hash starts %s", doctype, // hex_str(signed_digest,4)); - if (memcmp(digest, signed_digest, digest_len)) { + if (tor_memneq(digest, signed_digest, digest_len)) { log_warn(LD_DIR, "Error reading %s: signature does not match.", doctype); tor_free(signed_digest); return -1; @@ -1208,7 +1208,8 @@ router_parse_list_from_string(const char **s, const char *eos, prepend_annotations); if (router) { log_debug(LD_DIR, "Read router '%s', purpose '%s'", - router->nickname, router_purpose_to_string(router->purpose)); + router_describe(router), + router_purpose_to_string(router->purpose)); signed_desc = &router->cache_info; elt = router; } @@ -1459,6 +1460,11 @@ router_parse_entry_from_string(const char *s, const char *end, goto err; tok = find_by_keyword(tokens, K_ONION_KEY); + if (!crypto_pk_public_exponent_ok(tok->key)) { + log_warn(LD_DIR, + "Relay's onion key had invalid exponent."); + goto err; + } router->onion_pkey = tok->key; tok->key = NULL; /* Prevent free */ @@ -1480,7 +1486,7 @@ router_parse_entry_from_string(const char *s, const char *end, escaped(tok->args[0])); goto err; } - if (memcmp(d,router->cache_info.identity_digest, DIGEST_LEN)!=0) { + if (tor_memneq(d,router->cache_info.identity_digest, DIGEST_LEN)) { log_warn(LD_DIR, "Fingerprint '%s' does not match identity digest.", tok->args[0]); goto err; @@ -1528,10 +1534,10 @@ router_parse_entry_from_string(const char *s, const char *end, } } - if ((tok = find_opt_by_keyword(tokens, K_CACHES_EXTRA_INFO))) + if (find_opt_by_keyword(tokens, K_CACHES_EXTRA_INFO)) router->caches_extra_info = 1; - if ((tok = find_opt_by_keyword(tokens, K_ALLOW_SINGLE_HOP_EXITS))) + if (find_opt_by_keyword(tokens, K_ALLOW_SINGLE_HOP_EXITS)) router->allow_single_hop_exits = 1; if ((tok = find_opt_by_keyword(tokens, K_EXTRA_INFO_DIGEST))) { @@ -1544,7 +1550,7 @@ router_parse_entry_from_string(const char *s, const char *end, } } - if ((tok = find_opt_by_keyword(tokens, K_HIDDEN_SERVICE_DIR))) { + if (find_opt_by_keyword(tokens, K_HIDDEN_SERVICE_DIR)) { router->wants_to_be_hs_dir = 1; } @@ -1795,7 +1801,7 @@ authority_cert_parse_from_string(const char *s, const char **end_of_string) cert->cache_info.identity_digest)) goto err; - if (memcmp(cert->cache_info.identity_digest, fp_declared, DIGEST_LEN)) { + if (tor_memneq(cert->cache_info.identity_digest, fp_declared, DIGEST_LEN)) { log_warn(LD_DIR, "Digest of certificate key didn't match declared " "fingerprint"); goto err; @@ -1843,7 +1849,7 @@ authority_cert_parse_from_string(const char *s, const char **end_of_string) * buy us much. */ if (old_cert->cache_info.signed_descriptor_len == len && old_cert->cache_info.signed_descriptor_body && - !memcmp(s, old_cert->cache_info.signed_descriptor_body, len)) { + tor_memeq(s, old_cert->cache_info.signed_descriptor_body, len)) { log_debug(LD_DIR, "We already checked the signature on this " "certificate; no need to do so again."); found = 1; @@ -2203,7 +2209,7 @@ int compare_routerstatus_entries(const void **_a, const void **_b) { const routerstatus_t *a = *_a, *b = *_b; - return memcmp(a->identity_digest, b->identity_digest, DIGEST_LEN); + return fast_memcmp(a->identity_digest, b->identity_digest, DIGEST_LEN); } /** Helper: used in call to _smartlist_uniq to clear out duplicate entries. */ @@ -2296,7 +2302,7 @@ networkstatus_v2_parse_from_string(const char *s) log_warn(LD_DIR, "Couldn't compute signing key digest"); goto err; } - if (memcmp(tmp_digest, ns->identity_digest, DIGEST_LEN)) { + if (tor_memneq(tmp_digest, ns->identity_digest, DIGEST_LEN)) { log_warn(LD_DIR, "network-status fingerprint did not match dir-signing-key"); goto err; @@ -2497,7 +2503,7 @@ networkstatus_verify_bw_weights(networkstatus_t *ns) } } else { log_warn(LD_BUG, "Missing consensus bandwidth for router %s", - rs->nickname); + routerstatus_describe(rs)); } } SMARTLIST_FOREACH_END(rs); @@ -3000,7 +3006,7 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out, goto err; } if (ns->type != NS_TYPE_CONSENSUS && - memcmp(ns->cert->cache_info.identity_digest, + tor_memneq(ns->cert->cache_info.identity_digest, voter->identity_digest, DIGEST_LEN)) { log_warn(LD_DIR,"Mismatch between identities in certificate and vote"); goto err; @@ -3106,7 +3112,8 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out, rs1 = smartlist_get(ns->routerstatus_list, i-1); rs2 = smartlist_get(ns->routerstatus_list, i); } - if (memcmp(rs1->identity_digest, rs2->identity_digest, DIGEST_LEN) >= 0) { + if (fast_memcmp(rs1->identity_digest, rs2->identity_digest, DIGEST_LEN) + >= 0) { log_warn(LD_DIR, "Vote networkstatus entries not sorted by identity " "digest"); goto err; @@ -3225,7 +3232,7 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out, } if (ns->type != NS_TYPE_CONSENSUS) { - if (memcmp(declared_identity, ns->cert->cache_info.identity_digest, + if (tor_memneq(declared_identity, ns->cert->cache_info.identity_digest, DIGEST_LEN)) { log_warn(LD_DIR, "Digest mismatch between declared and actual on " "network-status vote."); @@ -3505,10 +3512,10 @@ networkstatus_parse_detached_signatures(const char *s, const char *eos) siglist = detached_get_signatures(sigs, flavor); is_duplicate = 0; - SMARTLIST_FOREACH(siglist, document_signature_t *, s, { - if (s->alg == alg && - !memcmp(id_digest, s->identity_digest, DIGEST_LEN) && - !memcmp(sk_digest, s->signing_key_digest, DIGEST_LEN)) { + SMARTLIST_FOREACH(siglist, document_signature_t *, dsig, { + if (dsig->alg == alg && + tor_memeq(id_digest, dsig->identity_digest, DIGEST_LEN) && + tor_memeq(sk_digest, dsig->signing_key_digest, DIGEST_LEN)) { is_duplicate = 1; } }); @@ -3767,9 +3774,9 @@ token_check_object(memarea_t *area, const char *kwd, break; case NEED_KEY_1024: /* There must be a 1024-bit public key. */ case NEED_SKEY_1024: /* There must be a 1024-bit private key. */ - if (tok->key && crypto_pk_keysize(tok->key) != PK_BYTES) { + if (tok->key && crypto_pk_num_bits(tok->key) != PK_BYTES*8) { tor_snprintf(ebuf, sizeof(ebuf), "Wrong size on key for %s: %d bits", - kwd, (int)crypto_pk_keysize(tok->key)); + kwd, crypto_pk_num_bits(tok->key)); RET_ERR(ebuf); } /* fall through */ @@ -4339,6 +4346,11 @@ microdescs_parse_from_string(const char *s, const char *eos, } tok = find_by_keyword(tokens, K_ONION_KEY); + if (!crypto_pk_public_exponent_ok(tok->key)) { + log_warn(LD_DIR, + "Relay's onion key had invalid exponent."); + goto next; + } md->onion_pkey = tok->key; tok->key = NULL; @@ -4546,7 +4558,7 @@ tor_version_compare(tor_version_t *a, tor_version_t *b) else if ((i = a->git_tag_len - b->git_tag_len)) return i; else if (a->git_tag_len) - return memcmp(a->git_tag, b->git_tag, a->git_tag_len); + return fast_memcmp(a->git_tag, b->git_tag, a->git_tag_len); else return 0; } @@ -4765,7 +4777,7 @@ rend_parse_v2_service_descriptor(rend_service_descriptor_t **parsed_out, crypto_pk_get_digest(result->pk, public_key_hash); rend_get_descriptor_id_bytes(test_desc_id, public_key_hash, secret_id_part); - if (memcmp(desc_id_out, test_desc_id, DIGEST_LEN)) { + if (tor_memneq(desc_id_out, test_desc_id, DIGEST_LEN)) { log_warn(LD_REND, "Parsed descriptor ID does not match " "computed descriptor ID."); goto err; @@ -4830,7 +4842,7 @@ rend_decrypt_introduction_points(char **ipos_decrypted, crypto_free_digest_env(digest); for (pos = 2; pos < 2 + client_entries_len; pos += REND_BASIC_AUTH_CLIENT_ENTRY_LEN) { - if (!memcmp(ipos_encrypted + pos, client_id, + if (tor_memeq(ipos_encrypted + pos, client_id, REND_BASIC_AUTH_CLIENT_ID_LEN)) { /* Attempt to decrypt introduction points. */ cipher = crypto_create_init_cipher(descriptor_cookie, 0); @@ -4854,7 +4866,7 @@ rend_decrypt_introduction_points(char **ipos_decrypted, tor_free(dec); return -1; } - if (memcmpstart(dec, declen, "introduction-point ")) { + if (fast_memcmpstart(dec, declen, "introduction-point ")) { log_warn(LD_REND, "Decrypted introduction points don't " "look like we could parse them."); tor_free(dec); @@ -4923,7 +4935,7 @@ rend_parse_introduction_points(rend_service_descriptor_t *parsed, parsed->intro_nodes = smartlist_create(); area = memarea_new(); - while (!memcmpstart(current_ipo, end_of_intro_points-current_ipo, + while (!fast_memcmpstart(current_ipo, end_of_intro_points-current_ipo, "introduction-point ")) { /* Determine end of string. */ const char *eos = tor_memstr(current_ipo, end_of_intro_points-current_ipo, @@ -4990,10 +5002,22 @@ rend_parse_introduction_points(rend_service_descriptor_t *parsed, } /* Parse onion key. */ tok = find_by_keyword(tokens, R_IPO_ONION_KEY); + if (!crypto_pk_public_exponent_ok(tok->key)) { + log_warn(LD_REND, + "Introduction point's onion key had invalid exponent."); + rend_intro_point_free(intro); + goto err; + } info->onion_key = tok->key; tok->key = NULL; /* Prevent free */ /* Parse service key. */ tok = find_by_keyword(tokens, R_IPO_SERVICE_KEY); + if (!crypto_pk_public_exponent_ok(tok->key)) { + log_warn(LD_REND, + "Introduction point key had invalid exponent."); + rend_intro_point_free(intro); + goto err; + } intro->intro_key = tok->key; tok->key = NULL; /* Prevent free */ /* Add extend info to list of introduction points. */ diff --git a/src/or/status.c b/src/or/status.c index 3a51c8b0a..acb8ba414 100644 --- a/src/or/status.c +++ b/src/or/status.c @@ -39,13 +39,15 @@ secs_to_uptime(long secs) switch (days) { case 0: - tor_asprintf(&uptime_string, "%d:%02d", hours, minutes); + tor_asprintf(&uptime_string, "%d:%02d hours", hours, minutes); break; case 1: - tor_asprintf(&uptime_string, "%ld day %d:%02d", days, hours, minutes); + tor_asprintf(&uptime_string, "%ld day %d:%02d hours", + days, hours, minutes); break; default: - tor_asprintf(&uptime_string, "%ld days %d:%02d", days, hours, minutes); + tor_asprintf(&uptime_string, "%ld days %d:%02d hours", + days, hours, minutes); break; } @@ -82,18 +84,16 @@ log_heartbeat(time_t now) char *bw_rcvd = NULL; char *uptime = NULL; const routerinfo_t *me; - const node_t *myself; - or_options_t *options = get_options(); - int is_server = server_mode(options); + const or_options_t *options = get_options(); (void)now; - if (is_server) { + if (public_server_mode(options)) { /* Let's check if we are in the current cached consensus. */ if (!(me = router_get_my_routerinfo())) return -1; /* Something stinks, we won't even attempt this. */ else - if (!(myself = node_get_by_id(me->cache_info.identity_digest))) + if (!node_get_by_id(me->cache_info.identity_digest)) log_fn(LOG_NOTICE, LD_HEARTBEAT, "Heartbeat: It seems like we are not " "in the cached consensus."); } |