diff options
Diffstat (limited to 'src')
47 files changed, 438 insertions, 333 deletions
diff --git a/src/app/config/app_config.md b/src/app/config/app_config.md index b359ce77f6..96a55494ff 100644 --- a/src/app/config/app_config.md +++ b/src/app/config/app_config.md @@ -2,5 +2,4 @@ @brief app/config: Top-level configuration code Refactoring this module is a work in progress, see -[ticket 29211](https://trac.torproject.org/projects/tor/ticket/29211). - +[ticket 29211](https://bugs.torproject.org/tpo/core/tor/29211) diff --git a/src/app/config/config.c b/src/app/config/config.c index 26be5d85d0..5c8a3792ee 100644 --- a/src/app/config/config.c +++ b/src/app/config/config.c @@ -3592,7 +3592,7 @@ options_validate_cb(const void *old_options_, void *options_, char **msg) "configured. This is bad because it's very easy to locate your " "entry guard which can then lead to the deanonymization of your " "hidden service -- for more details, see " - "https://trac.torproject.org/projects/tor/ticket/14917. " + "https://bugs.torproject.org/tpo/core/tor/14917. " "For this reason, the use of one EntryNodes with an hidden " "service is prohibited until a better solution is found."); return -1; @@ -3609,7 +3609,7 @@ options_validate_cb(const void *old_options_, void *options_, char **msg) "be harmful to the service anonymity. Because of this, we " "recommend you either don't do that or make sure you know what " "you are doing. For more details, please look at " - "https://trac.torproject.org/projects/tor/ticket/21155."); + "https://bugs.torproject.org/tpo/core/tor/21155."); } /* Single Onion Services: non-anonymous hidden services */ @@ -4050,8 +4050,11 @@ options_validate_cb(const void *old_options_, void *options_, char **msg) * actual maximum value. We clip this value if it's too low, and autodetect * it if it's set to 0. */ STATIC uint64_t -compute_real_max_mem_in_queues(const uint64_t val, int log_guess) +compute_real_max_mem_in_queues(const uint64_t val, bool is_server) { +#define MIN_SERVER_MB 64 +#define MIN_UNWARNED_SERVER_MB 256 +#define MIN_UNWARNED_CLIENT_MB 64 uint64_t result; if (val == 0) { @@ -4109,7 +4112,7 @@ compute_real_max_mem_in_queues(const uint64_t val, int log_guess) result = avail; } } - if (log_guess && ! notice_sent) { + if (is_server && ! notice_sent) { log_notice(LD_CONFIG, "%sMaxMemInQueues is set to %"PRIu64" MB. " "You can override this by setting MaxMemInQueues by hand.", ram ? "Based on detected system memory, " : "", @@ -4117,10 +4120,24 @@ compute_real_max_mem_in_queues(const uint64_t val, int log_guess) notice_sent = 1; } return result; - } else if (val < ONE_GIGABYTE / 4) { - log_warn(LD_CONFIG, "MaxMemInQueues must be at least 256 MB for now. " - "Ideally, have it as large as you can afford."); - return ONE_GIGABYTE / 4; + } else if (is_server && val < ONE_MEGABYTE * MIN_SERVER_MB) { + /* We can't configure less than this much on a server. */ + log_warn(LD_CONFIG, "MaxMemInQueues must be at least %d MB on servers " + "for now. Ideally, have it as large as you can afford.", + MIN_SERVER_MB); + return MIN_SERVER_MB * ONE_MEGABYTE; + } else if (is_server && val < ONE_MEGABYTE * MIN_UNWARNED_SERVER_MB) { + /* On a server, if it's less than this much, we warn that things + * may go badly. */ + log_warn(LD_CONFIG, "MaxMemInQueues is set to a low value; if your " + "relay doesn't work, this may be the reason why."); + return val; + } else if (! is_server && val < ONE_MEGABYTE * MIN_UNWARNED_CLIENT_MB) { + /* On a client, if it's less than this much, we warn that things + * may go badly. */ + log_warn(LD_CONFIG, "MaxMemInQueues is set to a low value; if your " + "client doesn't work, this may be the reason why."); + return val; } else { /* The value was fine all along */ return val; diff --git a/src/app/config/config.h b/src/app/config/config.h index ee39490072..e95ef4a728 100644 --- a/src/app/config/config.h +++ b/src/app/config/config.h @@ -291,7 +291,7 @@ STATIC int parse_dir_authority_line(const char *line, STATIC int parse_dir_fallback_line(const char *line, int validate_only); STATIC uint64_t compute_real_max_mem_in_queues(const uint64_t val, - int log_guess); + bool is_server); STATIC int open_and_add_file_log(const log_severity_list_t *severity, const char *fname, int truncate_log); diff --git a/src/app/config/resolve_addr.c b/src/app/config/resolve_addr.c index a153d63974..b37707d2da 100644 --- a/src/app/config/resolve_addr.c +++ b/src/app/config/resolve_addr.c @@ -787,7 +787,8 @@ MOCK_IMPL(bool, is_local_to_resolve_addr, (const tor_addr_t *addr)) { const int family = tor_addr_family(addr); - const tor_addr_t *last_resolved_addr = &last_resolved_addrs[family]; + const tor_addr_t *last_resolved_addr = + &last_resolved_addrs[af_to_idx(family)]; /* Internal address is always local. */ if (tor_addr_is_internal(addr, 0)) { diff --git a/src/core/mainloop/connection.c b/src/core/mainloop/connection.c index 7f4c6a5f48..82886ccd0b 100644 --- a/src/core/mainloop/connection.c +++ b/src/core/mainloop/connection.c @@ -82,6 +82,7 @@ #include "core/or/policies.h" #include "core/or/reasons.h" #include "core/or/relay.h" +#include "core/or/status.h" #include "core/or/crypt_path.h" #include "core/proto/proto_haproxy.h" #include "core/proto/proto_http.h" @@ -2042,6 +2043,9 @@ connection_handle_listener_read(connection_t *conn, int new_type) connection_mark_for_close(newconn); return 0; } + + note_connection(true /* inbound */, conn->socket_family); + return 0; } @@ -2213,6 +2217,8 @@ connection_connect_sockaddr,(connection_t *conn, } } + note_connection(false /* outbound */, conn->socket_family); + /* it succeeded. we're connected. */ log_fn(inprogress ? LOG_DEBUG : LOG_INFO, LD_NET, "Connection to socket %s (sock "TOR_SOCKET_T_FORMAT").", diff --git a/src/core/or/channel.c b/src/core/or/channel.c index 91f083ec00..d082174dc8 100644 --- a/src/core/or/channel.c +++ b/src/core/or/channel.c @@ -871,6 +871,8 @@ channel_init(channel_t *chan) /* Channel is not in the scheduler heap. */ chan->sched_heap_idx = -1; + + tor_addr_make_unspec(&chan->addr_according_to_peer); } /** diff --git a/src/core/or/channel.h b/src/core/or/channel.h index 10b80aa7d5..606b0730b8 100644 --- a/src/core/or/channel.h +++ b/src/core/or/channel.h @@ -236,6 +236,9 @@ struct channel_t { /** The handle to this channel (to free on canceled timers) */ struct channel_handle_t *timer_handle; + /** If not UNSPEC, the address that the peer says we have. */ + tor_addr_t addr_according_to_peer; + /** * These two fields specify the minimum and maximum negotiated timeout * values for inactivity (send or receive) before we decide to pad a diff --git a/src/core/or/channeltls.c b/src/core/or/channeltls.c index 51b772728e..a0debf8d22 100644 --- a/src/core/or/channeltls.c +++ b/src/core/or/channeltls.c @@ -1856,6 +1856,13 @@ channel_tls_process_netinfo_cell(cell_t *cell, channel_tls_t *chan) } } + if (me) { + /* We have a descriptor, so we are a relay: record the address that the + * other side said we had. */ + tor_addr_copy(&TLS_CHAN_TO_BASE(chan)->addr_according_to_peer, + &my_apparent_addr); + } + n_other_addrs = netinfo_cell_get_n_my_addrs(netinfo_cell); for (uint8_t i = 0; i < n_other_addrs; i++) { /* Consider all the other addresses; if any matches, this connection is diff --git a/src/core/or/circuitbuild.c b/src/core/or/circuitbuild.c index 76e9ccf0a5..ab4ce9f784 100644 --- a/src/core/or/circuitbuild.c +++ b/src/core/or/circuitbuild.c @@ -2148,7 +2148,7 @@ count_acceptable_nodes, (const smartlist_t *nodes, int direct)) * The alternative is building the circuit in reverse. Reverse calls to * onion_extend_cpath() (ie: select outer hops first) would then have the * property that you don't gain information about inner hops by observing - * outer ones. See https://trac.torproject.org/projects/tor/ticket/24487 + * outer ones. See https://bugs.torproject.org/tpo/core/tor/24487 * for this. * * (Note further that we still exclude the exit to prevent A - B - A diff --git a/src/core/or/circuitlist.c b/src/core/or/circuitlist.c index c0c28c9e2d..c31fe00dea 100644 --- a/src/core/or/circuitlist.c +++ b/src/core/or/circuitlist.c @@ -2144,7 +2144,7 @@ circuit_mark_all_dirty_circs_as_unusable(void) * This function is in the critical path of circuit_mark_for_close(). * It must be (and is) O(1)! * - * See https://trac.torproject.org/projects/tor/ticket/23512. + * See https://bugs.torproject.org/tpo/core/tor/23512 */ void circuit_synchronize_written_or_bandwidth(const circuit_t *c, diff --git a/src/core/or/or_circuit_st.h b/src/core/or/or_circuit_st.h index 9bfe999728..4e17b1c143 100644 --- a/src/core/or/or_circuit_st.h +++ b/src/core/or/or_circuit_st.h @@ -75,6 +75,10 @@ struct or_circuit_t { /** If set, the DoS defenses are enabled on this circuit meaning that the * introduce2_bucket is initialized and used. */ unsigned int introduce2_dos_defense_enabled : 1; + /** If set, the DoS defenses were explicitly enabled through the + * ESTABLISH_INTRO cell extension. If unset, the consensus is used to learn + * if the defenses can be enabled or not. */ + unsigned int introduce2_dos_defense_explicit : 1; /** INTRODUCE2 cell bucket controlling how much can go on this circuit. Only * used if this is a service introduction circuit at the intro point diff --git a/src/core/or/status.c b/src/core/or/status.c index ed8448883c..00a88a3178 100644 --- a/src/core/or/status.c +++ b/src/core/or/status.c @@ -113,6 +113,41 @@ log_onion_service_stats(void) hs_stats_get_n_rendezvous_launches()); } +/** + * @name connection counts for heartbeat + * + * Tracks incoming and outgoing connections on IPv4/IPv6, for heartbeat + * logs. + **/ +/**@{*/ +static unsigned n_incoming_ipv4; +static unsigned n_incoming_ipv6; +static unsigned n_outgoing_ipv4; +static unsigned n_outgoing_ipv6; +/**@}*/ + +/** + * Note that a connection has arrived or has been made, for use in the + * heartbeat message. + **/ +void +note_connection(bool inbound, int family) +{ + if (family == AF_INET) { + if (inbound) { + ++n_incoming_ipv4; + } else { + ++n_outgoing_ipv4; + } + } else if (family == AF_INET6) { + if (inbound) { + ++n_incoming_ipv6; + } else { + ++n_outgoing_ipv6; + } + } +} + /** Log a "heartbeat" message describing Tor's status and history so that the * user can know that there is indeed a running Tor. Return 0 on success and * -1 on failure. */ @@ -143,8 +178,12 @@ log_heartbeat(time_t now) bw_sent = bytes_to_usage(get_bytes_written()); log_fn(LOG_NOTICE, LD_HEARTBEAT, "Heartbeat: Tor's uptime is %s, with %d " - "circuits open. I've sent %s and received %s.%s", + "circuits open. I've sent %s and received %s. I've received %u " + "connections on IPv4 and %u on IPv6. I've made %u connections " + "with IPv4 and %u with IPv6.%s", uptime, count_circuits(), bw_sent, bw_rcvd, + n_incoming_ipv4, n_incoming_ipv6, + n_outgoing_ipv4, n_outgoing_ipv6, hibernating?" We are currently hibernating.":""); dirclient_dump_total_dls(); diff --git a/src/core/or/status.h b/src/core/or/status.h index 639f8cdf51..271e0dbc9a 100644 --- a/src/core/or/status.h +++ b/src/core/or/status.h @@ -11,6 +11,7 @@ #include "lib/testsupport/testsupport.h" +void note_connection(bool inbound, int family); int log_heartbeat(time_t now); #ifdef STATUS_PRIVATE diff --git a/src/core/proto/proto_socks.c b/src/core/proto/proto_socks.c index 198195c0ae..08febee5bb 100644 --- a/src/core/proto/proto_socks.c +++ b/src/core/proto/proto_socks.c @@ -67,8 +67,8 @@ log_unsafe_socks_warning(int socks_protocol, const char *address, "Tor only an IP address. Applications that do DNS resolves " "themselves may leak information. Consider using Socks4A " "(e.g. via privoxy or socat) instead. For more information, " - "please see https://wiki.torproject.org/TheOnionRouter/" - "TorFAQ#SOCKSAndDNS.%s", + "please see https://2019.www.torproject.org/docs/faq.html.en" + "#WarningsAboutSOCKSandDNSInformationLeaks.%s", socks_protocol, (int)port, safe_socks ? " Rejecting." : ""); diff --git a/src/ext/ed25519/donna/ed25519_tor.c b/src/ext/ed25519/donna/ed25519_tor.c index a5bb6f4e21..4b35c9f634 100644 --- a/src/ext/ed25519/donna/ed25519_tor.c +++ b/src/ext/ed25519/donna/ed25519_tor.c @@ -43,6 +43,7 @@ #include "ed25519-randombytes.h" #include "ed25519-hash.h" +#include "lib/crypt_ops/crypto_rand.h" #include "lib/crypt_ops/crypto_util.h" typedef unsigned char ed25519_signature[64]; diff --git a/src/feature/client/bridges.c b/src/feature/client/bridges.c index cc17e8fa67..59f79219cf 100644 --- a/src/feature/client/bridges.c +++ b/src/feature/client/bridges.c @@ -249,8 +249,8 @@ get_configured_bridge_by_exact_addr_port_digest(const tor_addr_t *addr, * address/port matches only. */ int addr_is_a_configured_bridge(const tor_addr_t *addr, - uint16_t port, - const char *digest) + uint16_t port, + const char *digest) { tor_assert(addr); return get_configured_bridge_by_addr_port_digest(addr, port, digest) ? 1 : 0; @@ -596,7 +596,7 @@ find_transport_name_by_bridge_addrport(const tor_addr_t *addr, uint16_t port) */ int get_transport_by_bridge_addrport(const tor_addr_t *addr, uint16_t port, - const transport_t **transport) + const transport_t **transport) { *transport = NULL; if (!bridge_list) diff --git a/src/feature/client/entrynodes.c b/src/feature/client/entrynodes.c index c51958acec..2104a622da 100644 --- a/src/feature/client/entrynodes.c +++ b/src/feature/client/entrynodes.c @@ -3139,9 +3139,9 @@ entry_guard_parse_from_state(const char *s) guard->sampled_idx = guard->confirmed_idx; } else { - log_warn(LD_GUARD, "The state file seems to be into a status that could" - " yield to weird entry node selection: we're missing both a" - " sampled_idx and a confirmed_idx."); + log_info(LD_GUARD, "The state file seems to be into a status that could" + " yield to weird entry node selection: we're missing both a" + " sampled_idx and a confirmed_idx."); guard->sampled_idx = invalid_sampled_idx++; } diff --git a/src/feature/control/control_hs.c b/src/feature/control/control_hs.c index c8de03b318..54b767cd0d 100644 --- a/src/feature/control/control_hs.c +++ b/src/feature/control/control_hs.c @@ -134,6 +134,13 @@ handle_control_onion_client_auth_add(control_connection_t *conn, } } SMARTLIST_FOREACH_END(flag); } + if (!strcasecmp(line->key, "ClientName")) { + if (strlen(line->value) > REND_CLIENTNAME_MAX_LEN) { + control_printf_endreply(conn, 512, "ClientName longer than %d chars", + REND_CLIENTNAME_MAX_LEN); + } + creds->client_name = tor_strdup(line->value); + } } hs_client_register_auth_status_t register_status; @@ -255,6 +262,10 @@ encode_client_auth_cred_for_control_port( } } + if (cred->client_name) { + smartlist_add_asprintf(control_line, " ClientName=%s", cred->client_name); + } + /* Join all the components into a single string */ msg_str = smartlist_join_strings(control_line, "", 0, NULL); diff --git a/src/feature/hs/hs_client.c b/src/feature/hs/hs_client.c index cde3560ebf..b67ff237b5 100644 --- a/src/feature/hs/hs_client.c +++ b/src/feature/hs/hs_client.c @@ -2169,6 +2169,8 @@ client_service_authorization_free_(hs_client_service_authorization_t *auth) return; } + tor_free(auth->client_name); + memwipe(auth, 0, sizeof(*auth)); tor_free(auth); } diff --git a/src/feature/hs/hs_client.h b/src/feature/hs/hs_client.h index a11caa309f..88dede8126 100644 --- a/src/feature/hs/hs_client.h +++ b/src/feature/hs/hs_client.h @@ -71,6 +71,9 @@ typedef struct hs_client_service_authorization_t { /** An onion address that is used to connect to the onion service. */ char onion_address[HS_SERVICE_ADDR_LEN_BASE32+1]; + /** An client name used to connect to the onion service. */ + char *client_name; + /* Optional flags for this client. */ int flags; } hs_client_service_authorization_t; diff --git a/src/feature/hs/hs_dos.c b/src/feature/hs/hs_dos.c index 1f7415a280..04c2bfbb89 100644 --- a/src/feature/hs/hs_dos.c +++ b/src/feature/hs/hs_dos.c @@ -93,6 +93,11 @@ update_intro_circuits(void) smartlist_t *intro_circs = hs_circuitmap_get_all_intro_circ_relay_side(); SMARTLIST_FOREACH_BEGIN(intro_circs, circuit_t *, circ) { + /* Ignore circuit if the defenses were set explicitly through the + * ESTABLISH_INTRO cell DoS extension. */ + if (TO_OR_CIRCUIT(circ)->introduce2_dos_defense_explicit) { + continue; + } /* Defenses might have been enabled or disabled. */ TO_OR_CIRCUIT(circ)->introduce2_dos_defense_enabled = consensus_param_introduce_defense_enabled; diff --git a/src/feature/hs/hs_intropoint.c b/src/feature/hs/hs_intropoint.c index e282d1f1bd..69d60f21c3 100644 --- a/src/feature/hs/hs_intropoint.c +++ b/src/feature/hs/hs_intropoint.c @@ -285,6 +285,11 @@ handle_establish_intro_cell_dos_extension( } } + /* At this point, the extension is valid so any values out of it implies + * that it was set explicitly and thus flag the circuit that it should not + * look at the consensus for that reason for the defenses' values. */ + circ->introduce2_dos_defense_explicit = 1; + /* A value of 0 is valid in the sense that we accept it but we still disable * the defenses so return false. */ if (intro2_rate_per_sec == 0 || intro2_burst_per_sec == 0) { diff --git a/src/feature/nodelist/routerlist.c b/src/feature/nodelist/routerlist.c index 9def90d8d5..fcaf507efc 100644 --- a/src/feature/nodelist/routerlist.c +++ b/src/feature/nodelist/routerlist.c @@ -89,6 +89,7 @@ #include "feature/nodelist/routerset.h" #include "feature/nodelist/torcert.h" #include "feature/relay/routermode.h" +#include "feature/relay/relay_find_addr.h" #include "feature/stats/rephist.h" #include "lib/crypt_ops/crypto_format.h" #include "lib/crypt_ops/crypto_rand.h" @@ -2772,12 +2773,27 @@ launch_dummy_descriptor_download_as_needed(time_t now, const or_options_t *options) { static time_t last_dummy_download = 0; + bool have_addr; + tor_addr_t addr_out; + + /* This dummy fetch only matter for relays. */ + if (!server_mode(options)) { + return; + } + + /* Lookup the address cache to learn if we have a good usable address. We + * still force relays to have an IPv4 so that alone is enough to learn if we + * need a lookup. In case we don't have one, we might want to attempt a + * dummy fetch to learn our address as a suggestion from an authority. */ + have_addr = relay_find_addr_to_publish(options, AF_INET, + RELAY_FIND_ADDR_CACHE_ONLY, + &addr_out); + /* XXXX+ we could be smarter here; see notes on bug 652. */ - /* If we're a server that doesn't have a configured address, we rely on - * directory fetches to learn when our address changes. So if we haven't - * tried to get any routerdescs in a long time, try a dummy fetch now. */ - if (!options->Address && - server_mode(options) && + /* If we're a server that doesn't have an address, we rely on directory + * fetches to learn when our address changes. So if we haven't tried to get + * any routerdescs in a long time, try a dummy fetch now. */ + if (!have_addr && last_descriptor_download_attempted + DUMMY_DOWNLOAD_INTERVAL < now && last_dummy_download + DUMMY_DOWNLOAD_INTERVAL < now) { last_dummy_download = now; diff --git a/src/feature/relay/circuitbuild_relay.c b/src/feature/relay/circuitbuild_relay.c index ad20e143be..64f3c341ae 100644 --- a/src/feature/relay/circuitbuild_relay.c +++ b/src/feature/relay/circuitbuild_relay.c @@ -588,13 +588,23 @@ onionskin_answer(struct or_circuit_t *circ, if ((!channel_is_local(circ->p_chan) || get_options()->ExtendAllowPrivateAddresses) && !channel_is_outgoing(circ->p_chan)) { - /* record that we could process create cells from a non-local conn - * that we didn't initiate; presumably this means that create cells - * can reach us too. */ - tor_addr_t remote_addr; - if (channel_get_addr_if_possible(circ->p_chan, &remote_addr)) { - int family = tor_addr_family(&remote_addr); - router_orport_found_reachable(family); + /* Okay, it's a create cell from a non-local connection + * that we didn't initiate. Presumably this means that create cells + * can reach us too. But what address can they reach us on? */ + const tor_addr_t *my_supposed_addr = &circ->p_chan->addr_according_to_peer; + if (router_addr_is_my_published_addr(my_supposed_addr)) { + /* Great, this create cell came on connection where the peer says + * that the our address is an address we're actually advertising! + * That should mean that we're reachable. But before we finally + * declare ourselves reachable, make sure that the address listed + * by the peer is the same family as the peer is actually using. + */ + tor_addr_t remote_addr; + int family = tor_addr_family(my_supposed_addr); + if (channel_get_addr_if_possible(circ->p_chan, &remote_addr) && + tor_addr_family(&remote_addr) == family) { + router_orport_found_reachable(family); + } } } diff --git a/src/feature/relay/relay_config.c b/src/feature/relay/relay_config.c index d3f904d286..6504c680eb 100644 --- a/src/feature/relay/relay_config.c +++ b/src/feature/relay/relay_config.c @@ -1037,7 +1037,7 @@ options_validate_relay_mode(const or_options_t *old_options, "Tor is currently configured as a relay and a hidden service. " "That's not very secure: you should probably run your hidden service " "in a separate Tor process, at least -- see " - "https://trac.torproject.org/8742"); + "https://bugs.torproject.org/tpo/core/tor/8742."); if (options->BridgeRelay && options->DirPort_set) { log_warn(LD_CONFIG, "Can't set a DirPort on a bridge relay; disabling " diff --git a/src/feature/relay/router.c b/src/feature/relay/router.c index 675b977ade..11847a2616 100644 --- a/src/feature/relay/router.c +++ b/src/feature/relay/router.c @@ -176,7 +176,7 @@ routerinfo_err_is_transient(int err) /** * For simplicity, we consider all errors other than * "not a server" transient - see discussion on - * https://trac.torproject.org/projects/tor/ticket/27034 + * https://bugs.torproject.org/tpo/core/tor/27034. */ return err != TOR_ROUTERINFO_ERROR_NOT_A_SERVER; } @@ -1729,6 +1729,31 @@ router_is_me(const routerinfo_t *router) return router_digest_is_me(router->cache_info.identity_digest); } +/** + * Return true if we are a server, and if @a addr is an address we are + * currently publishing (or trying to publish) in our descriptor. + * Return false otherwise. + **/ +bool +router_addr_is_my_published_addr(const tor_addr_t *addr) +{ + IF_BUG_ONCE(!addr) + return false; + + const routerinfo_t *me = router_get_my_routerinfo(); + if (!me) + return false; + + switch (tor_addr_family(addr)) { + case AF_INET: + return tor_addr_eq(addr, &me->ipv4_addr); + case AF_INET6: + return tor_addr_eq(addr, &me->ipv6_addr); + default: + return false; + } +} + /** Return a routerinfo for this OR, rebuilding a fresh one if * necessary. Return NULL on error, or if called on an OP. */ MOCK_IMPL(const routerinfo_t *, diff --git a/src/feature/relay/router.h b/src/feature/relay/router.h index 89b4a479a4..f71ada8eb7 100644 --- a/src/feature/relay/router.h +++ b/src/feature/relay/router.h @@ -100,6 +100,7 @@ int router_digest_is_me(const char *digest); const uint8_t *router_get_my_id_digest(void); int router_extrainfo_digest_is_me(const char *digest); int router_is_me(const routerinfo_t *router); +bool router_addr_is_my_published_addr(const tor_addr_t *addr); int router_build_fresh_descriptor(routerinfo_t **r, extrainfo_t **e); int router_rebuild_descriptor(int force); char *router_dump_router_to_string(routerinfo_t *router, diff --git a/src/feature/rend/rendmid.c b/src/feature/rend/rendmid.c index a473f0c7e1..b497362857 100644 --- a/src/feature/rend/rendmid.c +++ b/src/feature/rend/rendmid.c @@ -343,10 +343,12 @@ rend_mid_rendezvous(or_circuit_t *circ, const uint8_t *request, goto err; } - /* Statistics: Mark this circuit as an RP circuit so that we collect - stats from it. */ + /* Statistics: Mark circuits as RP circuits */ if (options->HiddenServiceStatistics) { + /* `circ` is the RP <-> service circuit */ circ->circuit_carries_hs_traffic_stats = 1; + /* `rend_circ` is the client <-> RP circuit */ + rend_circ->circuit_carries_hs_traffic_stats = 1; } /* Send the RENDEZVOUS2 cell to the client. */ diff --git a/src/lib/fs/path.c b/src/lib/fs/path.c index f03cecf52d..1a15969419 100644 --- a/src/lib/fs/path.c +++ b/src/lib/fs/path.c @@ -532,7 +532,7 @@ unglob_win32(const char *pattern, int prev_sep, int next_sep) tor_free(path_until_glob); return result; } -#else /* !defined(_WIN32) */ +#elif HAVE_GLOB /** Same as opendir but calls sandbox_intern_string before */ static DIR * prot_opendir(const char *name) @@ -559,7 +559,7 @@ wrap_closedir(void *arg) { closedir(arg); } -#endif /* defined(_WIN32) */ +#endif /* defined(HAVE_GLOB) */ /** Return a new list containing the paths that match the pattern * <b>pattern</b>. Return NULL on error. On POSIX systems, errno is set by the @@ -568,14 +568,15 @@ wrap_closedir(void *arg) struct smartlist_t * tor_glob(const char *pattern) { - smartlist_t *result; + smartlist_t *result = NULL; + #ifdef _WIN32 // PathMatchSpec does not support forward slashes, change them to backslashes char *pattern_normalized = tor_strdup(pattern); tor_strreplacechar(pattern_normalized, '/', *PATH_SEPARATOR); result = get_glob_paths(pattern_normalized, unglob_win32, true); tor_free(pattern_normalized); -#else /* !(defined(_WIN32)) */ +#elif HAVE_GLOB /* !(defined(_WIN32)) */ glob_t matches; int flags = GLOB_ERR | GLOB_NOSORT; #ifdef GLOB_ALTDIRFUNC @@ -608,7 +609,11 @@ tor_glob(const char *pattern) smartlist_add(result, match); } globfree(&matches); -#endif /* defined(_WIN32) */ +#else + (void)pattern; + return result; +#endif /* !defined(HAVE_GLOB) */ + return result; } diff --git a/src/lib/log/ratelim.c b/src/lib/log/ratelim.c index ac401fb398..8dfaee3384 100644 --- a/src/lib/log/ratelim.c +++ b/src/lib/log/ratelim.c @@ -11,6 +11,7 @@ #include "lib/log/ratelim.h" #include "lib/malloc/malloc.h" #include "lib/string/printf.h" +#include "lib/intmath/muldiv.h" /** If the rate-limiter <b>lim</b> is ready at <b>now</b>, return the number * of calls to rate_limit_is_ready (including this one!) since the last time @@ -42,19 +43,24 @@ rate_limit_log(ratelim_t *lim, time_t now) { int n; if ((n = rate_limit_is_ready(lim, now))) { + time_t started_limiting = lim->started_limiting; + lim->started_limiting = 0; if (n == 1) { return tor_strdup(""); } else { char *cp=NULL; const char *opt_over = (n >= RATELIM_TOOMANY) ? "over " : ""; - /* XXXX this is not exactly correct: the messages could have occurred - * any time between the old value of lim->allowed and now. */ + unsigned difference = (unsigned)(now - started_limiting); + difference = round_to_next_multiple_of(difference, 60); tor_asprintf(&cp, " [%s%d similar message(s) suppressed in last %d seconds]", - opt_over, n-1, lim->rate); + opt_over, n-1, (int)difference); return cp; } } else { + if (lim->started_limiting == 0) { + lim->started_limiting = now; + } return NULL; } } diff --git a/src/lib/log/ratelim.h b/src/lib/log/ratelim.h index e9b55d40dc..9e202028cf 100644 --- a/src/lib/log/ratelim.h +++ b/src/lib/log/ratelim.h @@ -40,13 +40,19 @@ </pre> */ typedef struct ratelim_t { + /** How many seconds must elapse between log messages? */ int rate; + /** When did this limiter last allow a message to appear? */ time_t last_allowed; + /** When did this limiter start suppressing messages? */ + time_t started_limiting; + /** How many messages has this limiter suppressed since it last allowed + * one to appear? */ int n_calls_since_last_time; } ratelim_t; #ifndef COCCI -#define RATELIM_INIT(r) { (r), 0, 0 } +#define RATELIM_INIT(r) { (r), 0, 0, 0 } #endif #define RATELIM_TOOMANY (16*1000*1000) diff --git a/src/lib/string/compat_string.h b/src/lib/string/compat_string.h index f05265bdcc..5c9bf05ebd 100644 --- a/src/lib/string/compat_string.h +++ b/src/lib/string/compat_string.h @@ -42,7 +42,7 @@ static inline int strcasecmp(const char *a, const char *b) { * (If --enable-fragile-hardening is passed to configure, we use the hardened * variants, which do not suffer from this issue.) * - * See https://trac.torproject.org/projects/tor/ticket/15205 + * See https://bugs.torproject.org/tpo/core/tor/15205. */ #undef strlcat #undef strlcpy diff --git a/src/test/include.am b/src/test/include.am index 478547d655..816eba894e 100644 --- a/src/test/include.am +++ b/src/test/include.am @@ -25,7 +25,15 @@ TESTSCRIPTS = \ src/test/test_workqueue_socketpair.sh \ src/test/test_switch_id.sh \ src/test/test_cmdline.sh \ - src/test/test_parseconf.sh + src/test/test_parseconf.sh \ + src/test/unittest_part1.sh \ + src/test/unittest_part2.sh \ + src/test/unittest_part3.sh \ + src/test/unittest_part4.sh \ + src/test/unittest_part5.sh \ + src/test/unittest_part6.sh \ + src/test/unittest_part7.sh \ + src/test/unittest_part8.sh if USE_RUST TESTSCRIPTS += \ @@ -55,7 +63,7 @@ TESTSCRIPTS += \ scripts/maint/checkSpaceTest.sh endif -TESTS += src/test/test src/test/test-slow src/test/test-memwipe \ +TESTS += src/test/test-slow src/test/test-memwipe \ src/test/test_workqueue \ src/test/test_keygen.sh \ src/test/test_key_expiration.sh \ @@ -451,7 +459,15 @@ EXTRA_DIST += \ src/test/test_workqueue_pipe2.sh \ src/test/test_workqueue_socketpair.sh \ src/test/test_cmdline.sh \ - src/test/test_parseconf.sh + src/test/test_parseconf.sh \ + src/test/unittest_part1.sh \ + src/test/unittest_part2.sh \ + src/test/unittest_part3.sh \ + src/test/unittest_part4.sh \ + src/test/unittest_part5.sh \ + src/test/unittest_part6.sh \ + src/test/unittest_part7.sh \ + src/test/unittest_part8.sh test-rust: $(TESTS_ENVIRONMENT) "$(abs_top_srcdir)/src/test/test_rust.sh" diff --git a/src/test/test_hs_control.c b/src/test/test_hs_control.c index 1f574179e9..80bbf547dc 100644 --- a/src/test/test_hs_control.c +++ b/src/test/test_hs_control.c @@ -212,7 +212,8 @@ test_hs_control_good_onion_client_auth_add(void *arg) MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock); int retval; - ed25519_public_key_t service_identity_pk_2fv, service_identity_pk_jt4; + ed25519_public_key_t service_identity_pk_2fv, service_identity_pk_jt4, + service_identity_pk_jam; control_connection_t conn; char *args = NULL; char *cp1 = NULL; @@ -238,6 +239,12 @@ test_hs_control_good_onion_client_auth_add(void *arg) &service_identity_pk_jt4, NULL, NULL); tt_int_op(retval, OP_EQ, 0); + + retval = hs_parse_address( + "jamie3vkiwibfiwucd6vxijskbhpjdyajmzeor4mc4i7yopvpo4p7cyd", + &service_identity_pk_jam, + NULL, NULL); + tt_int_op(retval, OP_EQ, 0); } digest256map_t *client_auths = get_hs_client_auths_map(); @@ -268,10 +275,24 @@ test_hs_control_good_onion_client_auth_add(void *arg) cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz); tt_str_op(cp1, OP_EQ, "250 OK\r\n"); tor_free(cp1); + tor_free(args); + + /* Register second service (even with an unrecognized argument) */ + args = tor_strdup("jamie3vkiwibfiwucd6vxijskbhpjdyajmzeor4mc4i7yopvpo4p7cyd " + "x25519:FCV0c0ELDKKDpSFgVIB8Yow8Evj5iD+GoiTtK878NkQ= " + "ClientName=MeganNicole "); + + retval = handle_control_command(&conn, (uint32_t) strlen(args), args); + tt_int_op(retval, OP_EQ, 0); + + /* Check contents */ + cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz); + tt_str_op(cp1, OP_EQ, "250 OK\r\n"); + tor_free(cp1); client_auths = get_hs_client_auths_map(); tt_assert(client_auths); - tt_uint_op(digest256map_size(client_auths), OP_EQ, 2); + tt_uint_op(digest256map_size(client_auths), OP_EQ, 3); hs_client_service_authorization_t *client_2fv = digest256map_get(client_auths, service_identity_pk_2fv.pubkey); @@ -283,6 +304,11 @@ test_hs_control_good_onion_client_auth_add(void *arg) tt_assert(client_jt4); tt_int_op(client_jt4->flags, OP_EQ, 0); + hs_client_service_authorization_t *client_jam = + digest256map_get(client_auths, service_identity_pk_jam.pubkey); + tt_assert(client_jam); + tt_int_op(client_jam->flags, OP_EQ, 0); + /* Now let's VIEW the auth credentials */ tor_free(conn.current_cmd); conn.current_cmd = tor_strdup("ONION_CLIENT_AUTH_VIEW"); @@ -294,6 +320,9 @@ test_hs_control_good_onion_client_auth_add(void *arg) #define VIEW_CORRECT_REPLY_NO_ADDR "250-ONION_CLIENT_AUTH_VIEW\r\n" \ "250-CLIENT 2fvhjskjet3n5syd6yfg5lhvwcs62bojmthr35ko5bllr3iqdb4ctdyd " \ "x25519:iJ1tjKCrMAbiFT2bVrCjhbfMDnE1fpaRbIS5ZHKUvEQ=\r\n" \ + "250-CLIENT jamie3vkiwibfiwucd6vxijskbhpjdyajmzeor4mc4i7yopvpo4p7cyd " \ + "x25519:FCV0c0ELDKKDpSFgVIB8Yow8Evj5iD+GoiTtK878NkQ= " \ + "ClientName=MeganNicole\r\n" \ "250-CLIENT jt4grrjwzyz3pjkylwfau5xnjaj23vxmhskqaeyfhrfylelw4hvxcuyd " \ "x25519:eIIdIGoSZwI2Q/lSzpf92akGki5I+PZIDz37MA5BhlA=\r\n" \ "250 OK\r\n" @@ -364,7 +393,19 @@ test_hs_control_good_onion_client_auth_add(void *arg) /* Now also remove the other one */ tor_free(args); - args =tor_strdup("2fvhjskjet3n5syd6yfg5lhvwcs62bojmthr35ko5bllr3iqdb4ctdyd"); + args = + tor_strdup("2fvhjskjet3n5syd6yfg5lhvwcs62bojmthr35ko5bllr3iqdb4ctdyd"); + + retval = handle_control_command(&conn, (uint32_t) strlen(args), args); + tt_int_op(retval, OP_EQ, 0); + cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz); + tt_str_op(cp1, OP_EQ, "250 OK\r\n"); + tor_free(cp1); + + /* Now also remove the other one */ + tor_free(args); + args = + tor_strdup("jamie3vkiwibfiwucd6vxijskbhpjdyajmzeor4mc4i7yopvpo4p7cyd"); retval = handle_control_command(&conn, (uint32_t) strlen(args), args); tt_int_op(retval, OP_EQ, 0); diff --git a/src/test/test_logging.c b/src/test/test_logging.c index e09f7a21cd..58d0f24bd3 100644 --- a/src/test/test_logging.c +++ b/src/test/test_logging.c @@ -160,6 +160,7 @@ test_ratelim(void *arg) tor_free(msg); int i; + time_t first_suppressed_at = now + 60; for (i = 0; i < 9; ++i) { now += 60; /* one minute has passed. */ msg = rate_limit_log(&ten_min, now); @@ -167,12 +168,15 @@ test_ratelim(void *arg) tt_int_op(ten_min.last_allowed, OP_EQ, start); tt_int_op(ten_min.n_calls_since_last_time, OP_EQ, i + 1); } + tt_i64_op(ten_min.started_limiting, OP_EQ, first_suppressed_at); now += 240; /* Okay, we can be done. */ msg = rate_limit_log(&ten_min, now); tt_ptr_op(msg, OP_NE, NULL); tt_str_op(msg, OP_EQ, - " [9 similar message(s) suppressed in last 600 seconds]"); + " [9 similar message(s) suppressed in last 720 seconds]"); + tt_i64_op(now, OP_EQ, first_suppressed_at + 720); + done: tor_free(msg); } diff --git a/src/test/test_options.c b/src/test/test_options.c index 8e0d19f126..714ee4767f 100644 --- a/src/test/test_options.c +++ b/src/test/test_options.c @@ -1013,7 +1013,7 @@ test_options_validate__relay_with_hidden_services(void *ignored) "Tor is currently configured as a relay and a hidden service. " "That's not very secure: you should probably run your hidden servi" "ce in a separate Tor process, at least -- see " - "https://trac.torproject.org/8742\n"); + "https://bugs.torproject.org/tpo/core/tor/8742.\n"); done: teardown_capture_of_logs(); diff --git a/src/test/test_status.c b/src/test/test_status.c index 82afe0fd2a..b938b86326 100644 --- a/src/test/test_status.c +++ b/src/test/test_status.c @@ -26,6 +26,7 @@ #include "feature/nodelist/nodelist.h" #include "app/config/statefile.h" #include "lib/tls/tortls.h" +#include "test/log_test_helpers.h" #include "core/or/origin_circuit_st.h" #include "app/config/or_state_st.h" @@ -308,10 +309,6 @@ static int status_hb_not_in_consensus_public_server_mode( static const routerinfo_t *status_hb_not_in_consensus_get_my_routerinfo(void); static const node_t * status_hb_not_in_consensus_node_get_by_id( const char *identity_digest); -static void status_hb_not_in_consensus_logv( - int severity, log_domain_mask_t domain, const char *funcname, - const char *suffix, const char *format, va_list ap); -static int status_hb_not_in_consensus_logv_called = 0; static int status_hb_not_in_consensus_server_mode(const or_options_t *options); static routerinfo_t *mock_routerinfo; @@ -332,8 +329,6 @@ test_status_hb_not_in_consensus(void *arg) status_hb_not_in_consensus_get_my_routerinfo); MOCK(node_get_by_id, status_hb_not_in_consensus_node_get_by_id); - MOCK(logv, - status_hb_not_in_consensus_logv); MOCK(server_mode, status_hb_not_in_consensus_server_mode); @@ -344,18 +339,38 @@ test_status_hb_not_in_consensus(void *arg) onion_handshakes_assigned[ONION_HANDSHAKE_TYPE_NTOR] = 1; expected = 0; + setup_capture_of_logs(LOG_INFO); actual = log_heartbeat(0); - tt_int_op(actual, OP_EQ, expected); - tt_int_op(status_hb_not_in_consensus_logv_called, OP_EQ, 6); - done: + expect_log_msg("Heartbeat: It seems like we are " + "not in the cached consensus.\n"); + expect_log_msg("Heartbeat: Tor's uptime is 0:00 hours, " + "with 0 circuits open. " + "I've sent 0 kB and received 0 kB. " + "I've received 0 connections on IPv4 and 0 on IPv6. " + "I've made 0 connections with IPv4 and 0 with IPv6.\n"); + expect_log_msg("Average packaged cell fullness: 100.000%. " + "TLS write overhead: 0%\n"); + expect_log_msg("Circuit handshake stats since last time: 1/1 TAP, " + "1/1 NTor.\n"); + expect_log_msg("Since startup we initiated 0 and received 0 v1 " + "connections; initiated 0 and received 0 v2 connections; " + "initiated 0 and received 0 v3 connections; " + "initiated 0 and received 0 v4 connections; " + "initiated 0 and received 0 v5 connections.\n"); + expect_log_msg("DoS mitigation since startup: 0 circuits killed with " + "too many cells. [cc not enabled] [conn not enabled] " + "0 INTRODUCE2 rejected.\n"); + tt_int_op(mock_saved_log_n_entries(), OP_EQ, 6); + + done: + teardown_capture_of_logs(); UNMOCK(tls_get_write_overhead_ratio); UNMOCK(we_are_hibernating); UNMOCK(public_server_mode); UNMOCK(router_get_my_routerinfo); UNMOCK(node_get_by_id); - UNMOCK(logv); UNMOCK(server_mode); tor_free(mock_routerinfo); } @@ -396,76 +411,6 @@ status_hb_not_in_consensus_node_get_by_id(const char *identity_digest) return NULL; } -static void -status_hb_not_in_consensus_logv(int severity, log_domain_mask_t domain, - const char *funcname, const char *suffix, const char *format, va_list ap) -{ - switch (status_hb_not_in_consensus_logv_called) - { - case 0: - tt_int_op(severity, OP_EQ, LOG_NOTICE); - tt_u64_op(domain, OP_EQ, LD_HEARTBEAT); - tt_ptr_op(strstr(funcname, "log_heartbeat"), OP_NE, NULL); - tt_ptr_op(suffix, OP_EQ, NULL); - tt_str_op(format, OP_EQ, - "Heartbeat: It seems like we are not in the cached consensus."); - break; - case 1: - tt_int_op(severity, OP_EQ, LOG_NOTICE); - tt_u64_op(domain, OP_EQ, LD_HEARTBEAT); - tt_ptr_op(strstr(funcname, "log_heartbeat"), OP_NE, NULL); - tt_ptr_op(suffix, OP_EQ, NULL); - tt_str_op(format, OP_EQ, - "Heartbeat: Tor's uptime is %s, with %d circuits open. " - "I've sent %s and received %s.%s"); - tt_str_op(va_arg(ap, char *), OP_EQ, "0:00 hours"); /* uptime */ - tt_int_op(va_arg(ap, int), OP_EQ, 0); /* count_circuits() */ - tt_str_op(va_arg(ap, char *), OP_EQ, "0 kB"); /* bw_sent */ - tt_str_op(va_arg(ap, char *), OP_EQ, "0 kB"); /* bw_rcvd */ - tt_str_op(va_arg(ap, char *), OP_EQ, ""); /* hibernating */ - break; - case 2: - tt_int_op(severity, OP_EQ, LOG_INFO); - break; - case 3: - tt_int_op(severity, OP_EQ, LOG_NOTICE); - tt_u64_op(domain, OP_EQ, LD_HEARTBEAT); - tt_ptr_op(strstr(funcname, "rep_hist_log_circuit_handshake_stats"), - OP_NE, NULL); - tt_ptr_op(suffix, OP_EQ, NULL); - tt_str_op(format, OP_EQ, - "Circuit handshake stats since last time: %d/%d TAP, %d/%d NTor."); - tt_int_op(va_arg(ap, int), OP_EQ, 1); /* handshakes assigned (TAP) */ - tt_int_op(va_arg(ap, int), OP_EQ, 1); /* handshakes requested (TAP) */ - tt_int_op(va_arg(ap, int), OP_EQ, 1); /* handshakes assigned (NTOR) */ - tt_int_op(va_arg(ap, int), OP_EQ, 1); /* handshakes requested (NTOR) */ - break; - case 4: - tt_int_op(severity, OP_EQ, LOG_NOTICE); - tt_u64_op(domain, OP_EQ, LD_HEARTBEAT); - tt_ptr_op(strstr(funcname, "rep_hist_log_link_protocol_counts"), - OP_NE, NULL); - break; - case 5: - tt_int_op(severity, OP_EQ, LOG_NOTICE); - tt_u64_op(domain, OP_EQ, LD_HEARTBEAT); - tt_str_op(format, OP_EQ, "DoS mitigation since startup:%s%s%s%s%s"); - tt_str_op(va_arg(ap, char *), OP_EQ, - " 0 circuits killed with too many cells."); - tt_str_op(va_arg(ap, char *), OP_EQ, " [cc not enabled]"); - tt_str_op(va_arg(ap, char *), OP_EQ, " [conn not enabled]"); - tt_str_op(va_arg(ap, char *), OP_EQ, ""); - tt_str_op(va_arg(ap, char *), OP_EQ, " 0 INTRODUCE2 rejected."); - break; - default: - tt_abort_msg("unexpected call to logv()"); // TODO: prettyprint args - break; - } - - done: - status_hb_not_in_consensus_logv_called++; -} - static int status_hb_not_in_consensus_server_mode(const or_options_t *options) { @@ -485,14 +430,8 @@ static int status_hb_simple_public_server_mode(const or_options_t *options); static long status_hb_simple_get_uptime(void); static uint64_t status_hb_simple_get_bytes_read(void); static uint64_t status_hb_simple_get_bytes_written(void); -static void status_hb_simple_logv(int severity, log_domain_mask_t domain, - const char *funcname, const char *suffix, - const char *format, va_list ap); -ATTR_UNUSED static int status_hb_simple_logv_called = 0; static int status_hb_simple_server_mode(const or_options_t *options); -static int status_hb_simple_n_msgs = 0; - static void test_status_hb_simple(void *arg) { @@ -511,27 +450,32 @@ test_status_hb_simple(void *arg) status_hb_simple_get_bytes_read); MOCK(get_bytes_written, status_hb_simple_get_bytes_written); - MOCK(logv, - status_hb_simple_logv); MOCK(server_mode, status_hb_simple_server_mode); log_global_min_severity_ = LOG_DEBUG; + setup_capture_of_logs(LOG_INFO); expected = 0; actual = log_heartbeat(0); tt_int_op(actual, OP_EQ, expected); - tt_int_op(status_hb_simple_n_msgs, OP_EQ, 1); + + expect_log_msg("Heartbeat: Tor's uptime is 0:00 hours, " + "with 0 circuits open. " + "I've sent 0 kB and received 0 kB. " + "I've received 0 connections on IPv4 and 0 on IPv6. " + "I've made 0 connections with IPv4 and 0 with IPv6. " + "We are currently hibernating.\n"); done: + teardown_capture_of_logs(); UNMOCK(tls_get_write_overhead_ratio); UNMOCK(we_are_hibernating); UNMOCK(public_server_mode); UNMOCK(get_uptime); UNMOCK(get_bytes_read); UNMOCK(get_bytes_written); - UNMOCK(logv); UNMOCK(server_mode); } @@ -573,32 +517,6 @@ status_hb_simple_get_bytes_written(void) return 0; } -static void -status_hb_simple_logv(int severity, log_domain_mask_t domain, - const char *funcname, - const char *suffix, const char *format, va_list ap) -{ - if (severity == LOG_INFO) - return; - ++status_hb_simple_n_msgs; - - tt_int_op(severity, OP_EQ, LOG_NOTICE); - tt_u64_op(domain, OP_EQ, LD_HEARTBEAT); - tt_ptr_op(strstr(funcname, "log_heartbeat"), OP_NE, NULL); - tt_ptr_op(suffix, OP_EQ, NULL); - tt_str_op(format, OP_EQ, - "Heartbeat: Tor's uptime is %s, with %d circuits open. " - "I've sent %s and received %s.%s"); - tt_str_op(va_arg(ap, char *), OP_EQ, "0:00 hours"); /* uptime */ - tt_int_op(va_arg(ap, int), OP_EQ, 0); /* count_circuits() */ - tt_str_op(va_arg(ap, char *), OP_EQ, "0 kB"); /* bw_sent */ - tt_str_op(va_arg(ap, char *), OP_EQ, "0 kB"); /* bw_rcvd */ - tt_str_op(va_arg(ap, char *), OP_EQ, " We are currently hibernating."); - - done: - ; -} - static int status_hb_simple_server_mode(const or_options_t *options) { @@ -620,11 +538,6 @@ static int status_hb_calls_log_accounting_public_server_mode( static long status_hb_calls_log_accounting_get_uptime(void); static uint64_t status_hb_calls_log_accounting_get_bytes_read(void); static uint64_t status_hb_calls_log_accounting_get_bytes_written(void); -static void status_hb_calls_log_accounting_logv( - int severity, log_domain_mask_t domain, - const char *funcname, const char *suffix, - const char *format, va_list ap); -static int status_hb_calls_log_accounting_logv_called = 0; static int status_hb_calls_log_accounting_server_mode( const or_options_t *options); static or_state_t * status_hb_calls_log_accounting_get_or_state(void); @@ -653,8 +566,6 @@ test_status_hb_calls_log_accounting(void *arg) status_hb_calls_log_accounting_get_bytes_read); MOCK(get_bytes_written, status_hb_calls_log_accounting_get_bytes_written); - MOCK(logv, - status_hb_calls_log_accounting_logv); MOCK(server_mode, status_hb_calls_log_accounting_server_mode); MOCK(get_or_state, @@ -666,20 +577,31 @@ test_status_hb_calls_log_accounting(void *arg) log_global_min_severity_ = LOG_DEBUG; + setup_capture_of_logs(LOG_NOTICE); expected = 0; actual = log_heartbeat(0); tt_int_op(actual, OP_EQ, expected); - tt_int_op(status_hb_calls_log_accounting_logv_called, OP_EQ, 3); + + expect_log_msg("Heartbeat: Tor's uptime is 0:00 hours, " + "with 0 circuits open. " + "I've sent 0 kB and received 0 kB. " + "I've received 0 connections on IPv4 and 0 on IPv6. " + "I've made 0 connections with IPv4 and 0 with IPv6.\n"); + + expect_log_msg_containing("Heartbeat: Accounting enabled. Sent: 0 kB, " + "Received: 0 kB, Used: 0 kB / 0 kB, Rule: max. " + "The current accounting interval ends on "); + tt_int_op(mock_saved_log_n_entries(), OP_EQ, 2); done: + teardown_capture_of_logs(); UNMOCK(tls_get_write_overhead_ratio); UNMOCK(we_are_hibernating); UNMOCK(public_server_mode); UNMOCK(get_uptime); UNMOCK(get_bytes_read); UNMOCK(get_bytes_written); - UNMOCK(logv); UNMOCK(server_mode); UNMOCK(accounting_is_enabled); UNMOCK(accounting_get_end_time); @@ -725,58 +647,6 @@ status_hb_calls_log_accounting_get_bytes_written(void) return 0; } -static void -status_hb_calls_log_accounting_logv(int severity, log_domain_mask_t domain, - const char *funcname, const char *suffix, const char *format, va_list ap) -{ - switch (status_hb_calls_log_accounting_logv_called) - { - case 0: - tt_int_op(severity, OP_EQ, LOG_NOTICE); - tt_u64_op(domain, OP_EQ, LD_HEARTBEAT); - tt_ptr_op(strstr(funcname, "log_heartbeat"), OP_NE, NULL); - tt_ptr_op(suffix, OP_EQ, NULL); - tt_str_op(format, OP_EQ, - "Heartbeat: Tor's uptime is %s, with %d circuits open. " - "I've sent %s and received %s.%s"); - tt_str_op(va_arg(ap, char *), OP_EQ, "0:00 hours"); /* uptime */ - tt_int_op(va_arg(ap, int), OP_EQ, 0); /* count_circuits() */ - tt_str_op(va_arg(ap, char *), OP_EQ, "0 kB"); /* bw_sent */ - tt_str_op(va_arg(ap, char *), OP_EQ, "0 kB"); /* bw_rcvd */ - tt_str_op(va_arg(ap, char *), OP_EQ, ""); /* hibernating */ - break; - case 1: - tt_int_op(severity, OP_EQ, LOG_NOTICE); - tt_u64_op(domain, OP_EQ, LD_HEARTBEAT); - tt_ptr_op(strstr(funcname, "log_accounting"), OP_NE, NULL); - tt_ptr_op(suffix, OP_EQ, NULL); - tt_str_op(format, OP_EQ, - "Heartbeat: Accounting enabled. Sent: %s, Received: %s, Used: %s / " - "%s, Rule: %s. The current accounting interval ends on %s, in %s."); - tt_str_op(va_arg(ap, char *), OP_EQ, "0 kB"); /* acc_sent */ - tt_str_op(va_arg(ap, char *), OP_EQ, "0 kB"); /* acc_rcvd */ - tt_str_op(va_arg(ap, char *), OP_EQ, "0 kB"); /* acc_used */ - tt_str_op(va_arg(ap, char *), OP_EQ, "0 kB"); /* acc_max */ - tt_str_op(va_arg(ap, char *), OP_EQ, "max"); /* acc_rule */ - /* format_local_iso_time uses local tz, so we can't just compare - * the string against a constant */ - char datetime[ISO_TIME_LEN+1]; - format_local_iso_time(datetime, 60); - tt_str_op(va_arg(ap, char *), OP_EQ, datetime); /* end_buf */ - tt_str_op(va_arg(ap, char *), OP_EQ, "0:01 hours"); /* remaining */ - break; - case 2: - tt_int_op(severity, OP_EQ, LOG_INFO); - break; - default: - tt_abort_msg("unexpected call to logv()"); // TODO: prettyprint args - break; - } - - done: - status_hb_calls_log_accounting_logv_called++; -} - static int status_hb_calls_log_accounting_server_mode(const or_options_t *options) { @@ -826,11 +696,6 @@ static int status_hb_packaged_cell_fullness_public_server_mode( static long status_hb_packaged_cell_fullness_get_uptime(void); static uint64_t status_hb_packaged_cell_fullness_get_bytes_read(void); static uint64_t status_hb_packaged_cell_fullness_get_bytes_written(void); -static void status_hb_packaged_cell_fullness_logv( - int severity, log_domain_mask_t domain, - const char *funcname, const char *suffix, - const char *format, va_list ap); -static int status_hb_packaged_cell_fullness_logv_called = 0; static int status_hb_packaged_cell_fullness_server_mode( const or_options_t *options); static int status_hb_packaged_cell_fullness_accounting_is_enabled( @@ -854,8 +719,6 @@ test_status_hb_packaged_cell_fullness(void *arg) status_hb_packaged_cell_fullness_get_bytes_read); MOCK(get_bytes_written, status_hb_packaged_cell_fullness_get_bytes_written); - MOCK(logv, - status_hb_packaged_cell_fullness_logv); MOCK(server_mode, status_hb_packaged_cell_fullness_server_mode); MOCK(accounting_is_enabled, @@ -865,12 +728,20 @@ test_status_hb_packaged_cell_fullness(void *arg) stats_n_data_bytes_packaged = RELAY_PAYLOAD_SIZE; stats_n_data_cells_packaged = 2; expected = 0; + setup_capture_of_logs(LOG_INFO); actual = log_heartbeat(0); tt_int_op(actual, OP_EQ, expected); - tt_int_op(status_hb_packaged_cell_fullness_logv_called, OP_EQ, 2); + expect_log_msg("Heartbeat: Tor's uptime is 0:00 hours, " + "with 0 circuits open. " + "I've sent 0 kB and received 0 kB. " + "I've received 0 connections on IPv4 and 0 on IPv6. " + "I've made 0 connections with IPv4 and 0 with IPv6.\n"); + expect_log_msg("Average packaged cell fullness: 50.000%. " + "TLS write overhead: 0%\n"); done: + teardown_capture_of_logs(); stats_n_data_bytes_packaged = 0; stats_n_data_cells_packaged = 0; UNMOCK(tls_get_write_overhead_ratio); @@ -879,7 +750,6 @@ test_status_hb_packaged_cell_fullness(void *arg) UNMOCK(get_uptime); UNMOCK(get_bytes_read); UNMOCK(get_bytes_written); - UNMOCK(logv); UNMOCK(server_mode); UNMOCK(accounting_is_enabled); } @@ -923,47 +793,6 @@ status_hb_packaged_cell_fullness_get_bytes_written(void) return 0; } -static void -status_hb_packaged_cell_fullness_logv(int severity, - log_domain_mask_t domain, const char *funcname, - const char *suffix, const char *format, va_list ap) -{ - switch (status_hb_packaged_cell_fullness_logv_called) - { - case 0: - tt_int_op(severity, OP_EQ, LOG_NOTICE); - tt_u64_op(domain, OP_EQ, LD_HEARTBEAT); - tt_ptr_op(strstr(funcname, "log_heartbeat"), OP_NE, NULL); - tt_ptr_op(suffix, OP_EQ, NULL); - tt_str_op(format, OP_EQ, - "Heartbeat: Tor's uptime is %s, with %d circuits open. " - "I've sent %s and received %s.%s"); - tt_str_op(va_arg(ap, char *), OP_EQ, "0:00 hours"); /* uptime */ - tt_int_op(va_arg(ap, int), OP_EQ, 0); /* count_circuits() */ - tt_str_op(va_arg(ap, char *), OP_EQ, "0 kB"); /* bw_sent */ - tt_str_op(va_arg(ap, char *), OP_EQ, "0 kB"); /* bw_rcvd */ - tt_str_op(va_arg(ap, char *), OP_EQ, ""); /* hibernating */ - break; - case 1: - tt_int_op(severity, OP_EQ, LOG_NOTICE); - tt_u64_op(domain, OP_EQ, LD_HEARTBEAT); - tt_ptr_op(strstr(funcname, "log_heartbeat"), OP_NE, NULL); - tt_ptr_op(suffix, OP_EQ, NULL); - tt_str_op(format, OP_EQ, - "Average packaged cell fullness: %2.3f%%. " - "TLS write overhead: %.f%%"); - tt_double_op(fabs(va_arg(ap, double) - 50.0), OP_LE, DBL_EPSILON); - tt_double_op(fabs(va_arg(ap, double) - 0.0), OP_LE, DBL_EPSILON); - break; - default: - tt_abort_msg("unexpected call to logv()"); // TODO: prettyprint args - break; - } - - done: - status_hb_packaged_cell_fullness_logv_called++; -} - static int status_hb_packaged_cell_fullness_server_mode(const or_options_t *options) { @@ -993,11 +822,6 @@ static int status_hb_tls_write_overhead_public_server_mode( static long status_hb_tls_write_overhead_get_uptime(void); static uint64_t status_hb_tls_write_overhead_get_bytes_read(void); static uint64_t status_hb_tls_write_overhead_get_bytes_written(void); -static void status_hb_tls_write_overhead_logv( - int severity, log_domain_mask_t domain, - const char *funcname, const char *suffix, - const char *format, va_list ap); -static int status_hb_tls_write_overhead_logv_called = 0; static int status_hb_tls_write_overhead_server_mode( const or_options_t *options); static int status_hb_tls_write_overhead_accounting_is_enabled( @@ -1021,8 +845,6 @@ test_status_hb_tls_write_overhead(void *arg) status_hb_tls_write_overhead_get_bytes_read); MOCK(get_bytes_written, status_hb_tls_write_overhead_get_bytes_written); - MOCK(logv, - status_hb_tls_write_overhead_logv); MOCK(server_mode, status_hb_tls_write_overhead_server_mode); MOCK(accounting_is_enabled, @@ -1031,19 +853,26 @@ test_status_hb_tls_write_overhead(void *arg) log_global_min_severity_ = LOG_DEBUG; expected = 0; + setup_capture_of_logs(LOG_NOTICE); actual = log_heartbeat(0); tt_int_op(actual, OP_EQ, expected); - tt_int_op(status_hb_tls_write_overhead_logv_called, OP_EQ, 2); + expect_log_msg("Heartbeat: Tor's uptime is 0:00 hours, " + "with 0 circuits open. " + "I've sent 0 kB and received 0 kB. " + "I've received 0 connections on IPv4 and 0 on IPv6. " + "I've made 0 connections with IPv4 and 0 with IPv6.\n"); + expect_log_msg("Average packaged cell fullness: 100.000%. " + "TLS write overhead: 100%\n"); done: + teardown_capture_of_logs(); UNMOCK(tls_get_write_overhead_ratio); UNMOCK(we_are_hibernating); UNMOCK(public_server_mode); UNMOCK(get_uptime); UNMOCK(get_bytes_read); UNMOCK(get_bytes_written); - UNMOCK(logv); UNMOCK(server_mode); UNMOCK(accounting_is_enabled); } @@ -1086,46 +915,6 @@ status_hb_tls_write_overhead_get_bytes_written(void) return 0; } -static void -status_hb_tls_write_overhead_logv(int severity, log_domain_mask_t domain, - const char *funcname, const char *suffix, const char *format, va_list ap) -{ - switch (status_hb_tls_write_overhead_logv_called) - { - case 0: - tt_int_op(severity, OP_EQ, LOG_NOTICE); - tt_u64_op(domain, OP_EQ, LD_HEARTBEAT); - tt_ptr_op(strstr(funcname, "log_heartbeat"), OP_NE, NULL); - tt_ptr_op(suffix, OP_EQ, NULL); - tt_str_op(format, OP_EQ, - "Heartbeat: Tor's uptime is %s, with %d circuits open. " - "I've sent %s and received %s.%s"); - tt_str_op(va_arg(ap, char *), OP_EQ, "0:00 hours"); /* uptime */ - tt_int_op(va_arg(ap, int), OP_EQ, 0); /* count_circuits() */ - tt_str_op(va_arg(ap, char *), OP_EQ, "0 kB"); /* bw_sent */ - tt_str_op(va_arg(ap, char *), OP_EQ, "0 kB"); /* bw_rcvd */ - tt_str_op(va_arg(ap, char *), OP_EQ, ""); /* hibernating */ - break; - case 1: - tt_int_op(severity, OP_EQ, LOG_NOTICE); - tt_u64_op(domain, OP_EQ, LD_HEARTBEAT); - tt_ptr_op(strstr(funcname, "log_heartbeat"), OP_NE, NULL); - tt_ptr_op(suffix, OP_EQ, NULL); - tt_str_op(format, OP_EQ, - "Average packaged cell fullness: %2.3f%%. " - "TLS write overhead: %.f%%"); - tt_int_op(fabs(va_arg(ap, double) - 100.0) <= DBL_EPSILON, OP_EQ, 1); - tt_double_op(fabs(va_arg(ap, double) - 100.0), OP_LE, DBL_EPSILON); - break; - default: - tt_abort_msg("unexpected call to logv()"); // TODO: prettyprint args - break; - } - - done: - status_hb_tls_write_overhead_logv_called++; -} - static int status_hb_tls_write_overhead_server_mode(const or_options_t *options) { diff --git a/src/test/test_util.c b/src/test/test_util.c index cab48cd514..1c555e4d06 100644 --- a/src/test/test_util.c +++ b/src/test/test_util.c @@ -4440,6 +4440,7 @@ test_util_glob(void *ptr) { (void)ptr; +#ifdef HAVE_GLOB smartlist_t *results = NULL; int r, i; char *dir1 = NULL, *dir2 = NULL, *forbidden = NULL, *dirname = NULL; @@ -4656,6 +4657,11 @@ test_util_glob(void *ptr) SMARTLIST_FOREACH(results, char *, f, tor_free(f)); smartlist_free(results); } +#else + tt_skip(); + done: + return; +#endif } static void @@ -4663,6 +4669,7 @@ test_util_get_glob_opened_files(void *ptr) { (void)ptr; +#ifdef HAVE_GLOB smartlist_t *results = NULL; int r, i; char *dir1 = NULL, *dir2 = NULL, *forbidden = NULL, *dirname = NULL; @@ -4853,6 +4860,11 @@ test_util_get_glob_opened_files(void *ptr) SMARTLIST_FOREACH(results, char *, f, tor_free(f)); smartlist_free(results); } +#else + tt_skip(); + done: + return; +#endif } static void diff --git a/src/test/testing_common.c b/src/test/testing_common.c index cd93055dfb..9b50de07a8 100644 --- a/src/test/testing_common.c +++ b/src/test/testing_common.c @@ -287,6 +287,8 @@ main(int c, const char **v) /* Don't add default logs; the tests manage their own. */ quiet_level = QUIET_SILENT; + unsigned num=1, den=1; + for (i_out = i = 1; i < c; ++i) { if (!strcmp(v[i], "--warn")) { loglevel = LOG_WARN; @@ -298,6 +300,19 @@ main(int c, const char **v) loglevel = LOG_DEBUG; } else if (!strcmp(v[i], "--accel")) { accel_crypto = 1; + } else if (!strcmp(v[i], "--fraction")) { + if (i+1 == c) { + printf("--fraction needs an argument.\n"); + return 1; + } + const char *fracstr = v[++i]; + char ch; + if (sscanf(fracstr, "%u/%u%c", &num, &den, &ch) != 2) { + printf("--fraction expects a fraction as an input.\n"); + } + if (den == 0 || num == 0 || num > den) { + printf("--fraction expects a valid fraction as an input.\n"); + } } else { v[i_out++] = v[i]; } @@ -375,6 +390,33 @@ main(int c, const char **v) smartlist_free(skip); } + if (den != 1) { + // count the tests. Linear but fast. + unsigned n_tests = 0; + struct testgroup_t *tg; + struct testcase_t *tc; + for (tg = testgroups; tg->prefix != NULL; ++tg) { + for (tc = tg->cases; tc->name != NULL; ++tc) { + ++n_tests; + } + } + // Which tests should we run? This can give iffy results if den is huge + // but it doesn't actually matter in practice. + unsigned tests_per_chunk = CEIL_DIV(n_tests, den); + unsigned start_at = (num-1) * tests_per_chunk; + + // Skip the tests that are outside of the range. + unsigned idx = 0; + for (tg = testgroups; tg->prefix != NULL; ++tg) { + for (tc = tg->cases; tc->name != NULL; ++tc) { + if (idx < start_at || idx >= start_at + tests_per_chunk) { + tc->flags |= TT_SKIP; + } + ++idx; + } + } + } + int have_failed = (tinytest_main(c, v, testgroups) != 0); free_pregenerated_keys(); diff --git a/src/test/unittest_part1.sh b/src/test/unittest_part1.sh new file mode 100755 index 0000000000..5be0f499f9 --- /dev/null +++ b/src/test/unittest_part1.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +"${abs_top_builddir:-.}/src/test/test" --fraction 1/8 diff --git a/src/test/unittest_part2.sh b/src/test/unittest_part2.sh new file mode 100755 index 0000000000..9a614eb8c1 --- /dev/null +++ b/src/test/unittest_part2.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +"${abs_top_builddir:-.}/src/test/test" --fraction 2/8 diff --git a/src/test/unittest_part3.sh b/src/test/unittest_part3.sh new file mode 100755 index 0000000000..5cbc3fe495 --- /dev/null +++ b/src/test/unittest_part3.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +"${abs_top_builddir:-.}/src/test/test" --fraction 3/8 diff --git a/src/test/unittest_part4.sh b/src/test/unittest_part4.sh new file mode 100755 index 0000000000..bc6fe01f68 --- /dev/null +++ b/src/test/unittest_part4.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +"${abs_top_builddir:-.}/src/test/test" --fraction 4/8 diff --git a/src/test/unittest_part5.sh b/src/test/unittest_part5.sh new file mode 100755 index 0000000000..9bbff34fb8 --- /dev/null +++ b/src/test/unittest_part5.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +"${abs_top_builddir:-.}/src/test/test" --fraction 5/8 diff --git a/src/test/unittest_part6.sh b/src/test/unittest_part6.sh new file mode 100755 index 0000000000..2d5eaa8a28 --- /dev/null +++ b/src/test/unittest_part6.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +"${abs_top_builddir:-.}/src/test/test" --fraction 6/8 diff --git a/src/test/unittest_part7.sh b/src/test/unittest_part7.sh new file mode 100755 index 0000000000..5e6ce2aea5 --- /dev/null +++ b/src/test/unittest_part7.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +"${abs_top_builddir:-.}/src/test/test" --fraction 7/8 diff --git a/src/test/unittest_part8.sh b/src/test/unittest_part8.sh new file mode 100755 index 0000000000..7fea9c9c7f --- /dev/null +++ b/src/test/unittest_part8.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +"${abs_top_builddir:-.}/src/test/test" --fraction 8/8 |