/* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** * \file selftest.c * \brief Relay self-testing * * Relays need to make sure that their own ports are reachable, and estimate * their own bandwidth, before publishing. */ #include "core/or/or.h" #include "app/config/config.h" #include "core/mainloop/connection.h" #include "core/mainloop/mainloop.h" #include "core/mainloop/netstatus.h" #include "core/or/circuitbuild.h" #include "core/or/circuitlist.h" #include "core/or/circuituse.h" #include "core/or/crypt_path_st.h" #include "core/or/extend_info_st.h" #include "core/or/origin_circuit_st.h" #include "core/or/relay.h" #include "feature/control/control_events.h" #include "feature/dirclient/dirclient.h" #include "feature/dircommon/directory.h" #include "feature/nodelist/authority_cert_st.h" #include "feature/nodelist/routerinfo.h" #include "feature/nodelist/routerinfo_st.h" #include "feature/nodelist/routerlist.h" // but... #include "feature/nodelist/routerset.h" #include "feature/nodelist/torcert.h" #include "feature/relay/relay_periodic.h" #include "feature/relay/router.h" #include "feature/relay/selftest.h" static bool have_orport_for_family(int family); /** Whether we can reach our IPv4 ORPort from the outside. */ static bool can_reach_or_port_ipv4 = false; /** Whether we can reach our IPv6 ORPort from the outside. */ static bool can_reach_or_port_ipv6 = false; /** Whether we can reach our DirPort from the outside. */ static bool can_reach_dir_port = false; /** Forget what we have learned about our reachability status. */ void router_reset_reachability(void) { can_reach_or_port_ipv4 = can_reach_or_port_ipv6 = can_reach_dir_port = false; } /** Return 1 if we won't do reachability checks, because: * - AssumeReachable is set, or * - the network is disabled. * Otherwise, return 0. */ static int router_reachability_checks_disabled(const or_options_t *options) { return options->AssumeReachable || net_is_disabled(); } /** Return 0 if we need to do an ORPort reachability check, because: * - no reachability check has been done yet, or * - we've initiated reachability checks, but none have succeeded. * Return 1 if we don't need to do an ORPort reachability check, because: * - we've seen a successful reachability check, or * - AssumeReachable is set, or * - the network is disabled. * If `family'`is AF_INET or AF_INET6, return true only when we should skip * the given family's orport check (Because it's been checked, or because we * aren't checking it.) If `family` is 0, return true if we can skip _all_ * orport checks. */ int router_should_skip_orport_reachability_check_family( const or_options_t *options, int family) { tor_assert_nonfatal(family == AF_INET || family == AF_INET6 || family == 0); int reach_checks_disabled = router_reachability_checks_disabled(options); if (reach_checks_disabled) { return true; } // Which reachability flags should we look at? const bool checking_ipv4 = (family == AF_INET || family == 0); const bool checking_ipv6 = (family == AF_INET6 || family == 0); if (checking_ipv4) { if (have_orport_for_family(AF_INET) && !can_reach_or_port_ipv4) { return false; } } if (checking_ipv6) { if (have_orport_for_family(AF_INET6) && !can_reach_or_port_ipv6) { return false; } } return true; } /** Return 0 if we need to do a DirPort reachability check, because: * - no reachability check has been done yet, or * - we've initiated reachability checks, but none have succeeded. * Return 1 if we don't need to do a DirPort reachability check, because: * - we've seen a successful reachability check, or * - there is no DirPort set, or * - AssumeReachable is set, or * - the network is disabled. */ int router_should_skip_dirport_reachability_check(const or_options_t *options) { int reach_checks_disabled = router_reachability_checks_disabled(options) || !options->DirPort_set; return reach_checks_disabled || can_reach_dir_port; } /** See if we currently believe our ORPort or DirPort to be * unreachable. If so, return 1 else return 0. */ static int router_should_check_reachability(int test_or, int test_dir) { const routerinfo_t *me = router_get_my_routerinfo(); const or_options_t *options = get_options(); if (!me) return 0; /* Doesn't check our IPv6 address, see #34065. */ if (routerset_contains_router(options->ExcludeNodes, me, -1) && options->StrictNodes) { /* If we've excluded ourself, and StrictNodes is set, we can't test * ourself. */ if (test_or || test_dir) { #define SELF_EXCLUDED_WARN_INTERVAL 3600 static ratelim_t warning_limit=RATELIM_INIT(SELF_EXCLUDED_WARN_INTERVAL); log_fn_ratelim(&warning_limit, LOG_WARN, LD_CIRC, "Can't peform self-tests for this relay: we have " "listed ourself in ExcludeNodes, and StrictNodes is set. " "We cannot learn whether we are usable, and will not " "be able to advertise ourself."); } return 0; } return 1; } /** * Return true if we have configured an ORPort for the given family that * we would like to advertise. * * Like other self-testing functions, this function looks at our most * recently built descriptor. **/ static bool have_orport_for_family(int family) { const routerinfo_t *me = router_get_my_routerinfo(); if (!me) return false; tor_addr_port_t ap; if (router_get_orport(me, &ap, family) < 0) { return false; } return true; } /** Allocate and return a new extend_info_t that can be used to build * a circuit to or through the router r, using an address from * family (if available). * * Clients don't have routerinfos, so this function should only be called on a * server. * * If the requested address is not available, returns NULL. */ static extend_info_t * extend_info_from_router(const routerinfo_t *r, int family) { crypto_pk_t *rsa_pubkey; extend_info_t *info; tor_addr_port_t ap; if (BUG(!r)) { return NULL; } /* Relays always assume that the first hop is reachable. They ignore * ReachableAddresses. */ tor_assert_nonfatal(router_or_conn_should_skip_reachable_address_check( get_options(), 0)); const ed25519_public_key_t *ed_id_key; if (r->cache_info.signing_key_cert) ed_id_key = &r->cache_info.signing_key_cert->signing_key; else ed_id_key = NULL; if (router_get_orport(r, &ap, family) < 0) { /* We don't have an ORPort for the requested family. */ return NULL; } rsa_pubkey = router_get_rsa_onion_pkey(r->onion_pkey, r->onion_pkey_len); info = extend_info_new(r->nickname, r->cache_info.identity_digest, ed_id_key, rsa_pubkey, r->onion_curve25519_pkey, &ap.addr, ap.port); crypto_pk_free(rsa_pubkey); return info; } /** Launch a self-testing circuit to one of our ORPorts, using an address from * family (if available). The circuit can be used to test reachability * or bandwidth. me is our own routerinfo. * * Logs an info-level status message. If orport_reachable is false, * call it a reachability circuit. Otherwise, call it a bandwidth circuit. * * See router_do_reachability_checks() for details. */ static void router_do_orport_reachability_checks(const routerinfo_t *me, int family, int orport_reachable) { extend_info_t *ei = extend_info_from_router(me, family); int ipv6_flags = (family == AF_INET6 ? CIRCLAUNCH_IS_IPV6_SELFTEST : 0); /* If we're trying to test IPv6, but we don't have an IPv6 ORPort, ei will * be NULL. */ if (ei) { const char *family_name = fmt_af_family(family); log_info(LD_CIRC, "Testing %s of my %s ORPort: %s.", !orport_reachable ? "reachability" : "bandwidth", family_name, fmt_addrport(&ei->addr, ei->port)); circuit_launch_by_extend_info(CIRCUIT_PURPOSE_TESTING, ei, CIRCLAUNCH_NEED_CAPACITY| CIRCLAUNCH_IS_INTERNAL| ipv6_flags); extend_info_free(ei); } } /** Launch a self-testing circuit, and ask an exit to connect to our DirPort. * me is our own routerinfo. * * Relays don't advertise IPv6 DirPorts, so this function only supports IPv4. * * See router_do_reachability_checks() for details. */ static void router_do_dirport_reachability_checks(const routerinfo_t *me) { tor_addr_port_t my_dirport; tor_addr_from_ipv4h(&my_dirport.addr, me->addr); my_dirport.port = me->dir_port; /* If there is already a pending connection, don't open another one. */ if (!connection_get_by_type_addr_port_purpose( CONN_TYPE_DIR, &my_dirport.addr, my_dirport.port, DIR_PURPOSE_FETCH_SERVERDESC)) { /* ask myself, via tor, for my server descriptor. */ directory_request_t *req = directory_request_new(DIR_PURPOSE_FETCH_SERVERDESC); directory_request_set_dir_addr_port(req, &my_dirport); directory_request_set_directory_id_digest(req, me->cache_info.identity_digest); /* ask via an anon circuit, connecting to our dirport. */ directory_request_set_indirection(req, DIRIND_ANON_DIRPORT); directory_request_set_resource(req, "authority.z"); directory_initiate_request(req); directory_request_free(req); } } /** Some time has passed, or we just got new directory information. * See if we currently believe our ORPort or DirPort to be * unreachable. If so, launch a new test for it. * * For ORPort, we simply try making a circuit that ends at ourselves. * Success is noticed in onionskin_answer(). * * For DirPort, we make a connection via Tor to our DirPort and ask * for our own server descriptor. * Success is noticed in connection_dir_client_reached_eof(). */ void router_do_reachability_checks(int test_or, int test_dir) { const routerinfo_t *me = router_get_my_routerinfo(); const or_options_t *options = get_options(); int orport_reachable_v4 = router_should_skip_orport_reachability_check_family(options, AF_INET); int orport_reachable_v6 = router_should_skip_orport_reachability_check_family(options, AF_INET6); if (router_should_check_reachability(test_or, test_dir)) { bool need_testing = !circuit_enough_testing_circs(); /* At the moment, tor relays believe that they are reachable when they * receive any create cell on an inbound connection, if the address * family is correct. */ if (test_or && (!orport_reachable_v4 || need_testing)) { router_do_orport_reachability_checks(me, AF_INET, orport_reachable_v4); } if (test_or && (!orport_reachable_v6 || need_testing)) { router_do_orport_reachability_checks(me, AF_INET6, orport_reachable_v6); } if (test_dir && !router_should_skip_dirport_reachability_check(options)) { router_do_dirport_reachability_checks(me); } } } /** If reachability testing is in progress, let the user know that it's * happening. * * If all is set, log a notice-level message. Return 1 if we did, or 0 if * we chose not to log anything, because we were unable to test reachability. */ int inform_testing_reachability(void) { char ipv4_or_buf[TOR_ADDRPORT_BUF_LEN]; char ipv6_or_buf[TOR_ADDRPORT_BUF_LEN]; char ipv4_dir_buf[TOR_ADDRPORT_BUF_LEN]; /* There's a race condition here, between: * - tor launching reachability tests, * - any circuits actually completing, * - routerinfo updates, and * - these log messages. * In rare cases, we might log the wrong ports, log when we didn't actually * start reachability tests, or fail to log after we actually started * reachability tests. * * After we separate the IPv4 and IPv6 reachability flags in #34067, tor * will test any IPv6 address that it discovers after launching reachability * checks. We'll deal with late disabled IPv6 ORPorts and IPv4 DirPorts, and * extra or skipped log messages in #34137. */ const routerinfo_t *me = router_get_my_routerinfo(); if (!me) return 0; /* IPv4 ORPort */ strlcpy(ipv4_or_buf, fmt_addr32_port(me->addr, me->or_port), sizeof(ipv4_or_buf)); control_event_server_status(LOG_NOTICE, "CHECKING_REACHABILITY ORADDRESS=%s", ipv4_or_buf); /* IPv6 ORPort */ const bool has_ipv6 = tor_addr_port_is_valid(&me->ipv6_addr, me->ipv6_orport, 0); if (has_ipv6) { strlcpy(ipv6_or_buf, fmt_addrport(&me->ipv6_addr, me->ipv6_orport), sizeof(ipv6_or_buf)); /* We'll add an IPv6 control event in #34068. */ } /* IPv4 DirPort (there are no advertised IPv6 DirPorts) */ if (me->dir_port) { strlcpy(ipv4_dir_buf, fmt_addr32_port(me->addr, me->dir_port), sizeof(ipv4_dir_buf)); control_event_server_status(LOG_NOTICE, "CHECKING_REACHABILITY DIRADDRESS=%s", ipv4_dir_buf); } log_notice(LD_OR, "Now checking whether ORPort%s %s%s%s%s%s %s reachable... " "(this may take up to %d minutes -- look for log " "messages indicating success)", has_ipv6 ? "s" : "", ipv4_or_buf, has_ipv6 ? " and " : "", has_ipv6 ? ipv6_or_buf : "", me->dir_port ? " and DirPort " : "", me->dir_port ? ipv4_dir_buf : "", has_ipv6 || me->dir_port ? "are" : "is", TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT/60); return 1; } /** * Return true if this module knows of no reason why we shouldn't publish * a server descriptor. **/ static bool ready_to_publish(const or_options_t *options) { return options->PublishServerDescriptor_ != NO_DIRINFO && router_should_skip_dirport_reachability_check(options) && router_should_skip_orport_reachability_check(options); } /** Annotate that we found our ORPort reachable with a given address * family. */ void router_orport_found_reachable(int family) { const routerinfo_t *me = router_get_my_routerinfo(); const or_options_t *options = get_options(); bool *can_reach_ptr; if (family == AF_INET) { can_reach_ptr = &can_reach_or_port_ipv4; } else if (family == AF_INET6) { can_reach_ptr = &can_reach_or_port_ipv6; } else { tor_assert_nonfatal_unreached(); return; } if (!*can_reach_ptr && me) { tor_addr_port_t ap; if (router_get_orport(me, &ap, family) < 0) { return; } char *address = tor_strdup(fmt_addrport_ap(&ap)); *can_reach_ptr = true; log_notice(LD_OR,"Self-testing indicates your ORPort %s is reachable from " "the outside. Excellent.%s", address, ready_to_publish(options) ? " Publishing server descriptor." : ""); mark_my_descriptor_dirty("ORPort found reachable"); /* This is a significant enough change to upload immediately, * at least in a test network */ if (options->TestingTorNetwork == 1) { reschedule_descriptor_update_check(); } control_event_server_status(LOG_NOTICE, "REACHABILITY_SUCCEEDED ORADDRESS=%s", address); tor_free(address); } } /** Annotate that we found our DirPort reachable. */ void router_dirport_found_reachable(void) { const routerinfo_t *me = router_get_my_routerinfo(); const or_options_t *options = get_options(); if (!can_reach_dir_port && me) { char *address = tor_dup_ip(me->addr); if (!address) return; can_reach_dir_port = true; log_notice(LD_DIRSERV,"Self-testing indicates your DirPort is reachable " "from the outside. Excellent.%s", ready_to_publish(options) ? " Publishing server descriptor." : ""); if (router_should_advertise_dirport(options, me->dir_port)) { mark_my_descriptor_dirty("DirPort found reachable"); /* This is a significant enough change to upload immediately, * at least in a test network */ if (options->TestingTorNetwork == 1) { reschedule_descriptor_update_check(); } } control_event_server_status(LOG_NOTICE, "REACHABILITY_SUCCEEDED DIRADDRESS=%s:%d", address, me->dir_port); tor_free(address); } } /** We have enough testing circuits open. Send a bunch of "drop" * cells down each of them, to exercise our bandwidth. * * May use IPv4 and IPv6 testing circuits (if available). */ void router_perform_bandwidth_test(int num_circs, time_t now) { int num_cells = (int)(get_options()->BandwidthRate * 10 / CELL_MAX_NETWORK_SIZE); int max_cells = num_cells < CIRCWINDOW_START ? num_cells : CIRCWINDOW_START; int cells_per_circuit = max_cells / num_circs; origin_circuit_t *circ = NULL; log_notice(LD_OR,"Performing bandwidth self-test...done."); while ((circ = circuit_get_next_by_pk_and_purpose(circ, NULL, CIRCUIT_PURPOSE_TESTING))) { /* dump cells_per_circuit drop cells onto this circ */ int i = cells_per_circuit; if (circ->base_.state != CIRCUIT_STATE_OPEN) continue; circ->base_.timestamp_dirty = now; while (i-- > 0) { if (relay_send_command_from_edge(0, TO_CIRCUIT(circ), RELAY_COMMAND_DROP, NULL, 0, circ->cpath->prev)<0) { return; /* stop if error */ } } } }