tor

The Tor anonymity network
git clone https://git.dasho.dev/tor.git
Log | Files | Refs | README | LICENSE

control_bootstrap.c (14007B)


      1 /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
      2 * Copyright (c) 2007-2021, The Tor Project, Inc. */
      3 /* See LICENSE for licensing information */
      4 
      5 /**
      6 * \file control_bootstrap.c
      7 * \brief Provide bootstrap progress events for the control port.
      8 */
      9 #include "core/or/or.h"
     10 
     11 #include "app/config/config.h"
     12 #include "core/mainloop/connection.h"
     13 #include "core/or/connection_or.h"
     14 #include "core/or/connection_st.h"
     15 #include "core/or/or_connection_st.h"
     16 #include "core/or/reasons.h"
     17 #include "feature/control/control_events.h"
     18 #include "feature/hibernate/hibernate.h"
     19 #include "lib/malloc/malloc.h"
     20 
     21 /** A sufficiently large size to record the last bootstrap phase string. */
     22 #define BOOTSTRAP_MSG_LEN 1024
     23 
     24 /** What was the last bootstrap phase message we sent? We keep track
     25 * of this so we can respond to getinfo status/bootstrap-phase queries. */
     26 static char last_sent_bootstrap_message[BOOTSTRAP_MSG_LEN];
     27 
     28 /** Table to convert bootstrap statuses to strings.  */
     29 static const struct {
     30  bootstrap_status_t status;
     31  const char *tag;
     32  const char *summary;
     33 } boot_to_str_tab[] = {
     34  { BOOTSTRAP_STATUS_UNDEF, "undef", "Undefined" },
     35  { BOOTSTRAP_STATUS_STARTING, "starting", "Starting" },
     36 
     37  /* Initial connection to any relay */
     38 
     39  { BOOTSTRAP_STATUS_CONN_PT, "conn_pt", "Connecting to pluggable transport" },
     40  { BOOTSTRAP_STATUS_CONN_DONE_PT, "conn_done_pt",
     41    "Connected to pluggable transport" },
     42  { BOOTSTRAP_STATUS_CONN_PROXY, "conn_proxy", "Connecting to proxy" },
     43  { BOOTSTRAP_STATUS_CONN_DONE_PROXY, "conn_done_proxy",
     44    "Connected to proxy" },
     45  { BOOTSTRAP_STATUS_CONN, "conn", "Connecting to a relay" },
     46  { BOOTSTRAP_STATUS_CONN_DONE, "conn_done", "Connected to a relay" },
     47  { BOOTSTRAP_STATUS_HANDSHAKE, "handshake",
     48    "Handshaking with a relay" },
     49  { BOOTSTRAP_STATUS_HANDSHAKE_DONE, "handshake_done",
     50    "Handshake with a relay done" },
     51 
     52  /* Loading directory info */
     53 
     54  { BOOTSTRAP_STATUS_ONEHOP_CREATE, "onehop_create",
     55    "Establishing an encrypted directory connection" },
     56  { BOOTSTRAP_STATUS_REQUESTING_STATUS, "requesting_status",
     57    "Asking for networkstatus consensus" },
     58  { BOOTSTRAP_STATUS_LOADING_STATUS, "loading_status",
     59    "Loading networkstatus consensus" },
     60  { BOOTSTRAP_STATUS_LOADING_KEYS, "loading_keys",
     61    "Loading authority key certs" },
     62  { BOOTSTRAP_STATUS_REQUESTING_DESCRIPTORS, "requesting_descriptors",
     63    "Asking for relay descriptors" },
     64  { BOOTSTRAP_STATUS_LOADING_DESCRIPTORS, "loading_descriptors",
     65    "Loading relay descriptors" },
     66  { BOOTSTRAP_STATUS_ENOUGH_DIRINFO, "enough_dirinfo",
     67    "Loaded enough directory info to build circuits" },
     68 
     69  /* Connecting to a relay for AP circuits */
     70 
     71  { BOOTSTRAP_STATUS_AP_CONN_PT, "ap_conn_pt",
     72    "Connecting to pluggable transport to build circuits" },
     73  { BOOTSTRAP_STATUS_AP_CONN_DONE_PT, "ap_conn_done_pt",
     74    "Connected to pluggable transport to build circuits" },
     75  { BOOTSTRAP_STATUS_AP_CONN_PROXY, "ap_conn_proxy",
     76    "Connecting to proxy to build circuits" },
     77  { BOOTSTRAP_STATUS_AP_CONN_DONE_PROXY, "ap_conn_done_proxy",
     78    "Connected to proxy to build circuits" },
     79  { BOOTSTRAP_STATUS_AP_CONN, "ap_conn",
     80    "Connecting to a relay to build circuits" },
     81  { BOOTSTRAP_STATUS_AP_CONN_DONE, "ap_conn_done",
     82    "Connected to a relay to build circuits" },
     83  { BOOTSTRAP_STATUS_AP_HANDSHAKE, "ap_handshake",
     84    "Finishing handshake with a relay to build circuits" },
     85  { BOOTSTRAP_STATUS_AP_HANDSHAKE_DONE, "ap_handshake_done",
     86    "Handshake finished with a relay to build circuits" },
     87 
     88  /* Creating AP circuits */
     89 
     90  { BOOTSTRAP_STATUS_CIRCUIT_CREATE, "circuit_create",
     91    "Establishing a Tor circuit" },
     92  { BOOTSTRAP_STATUS_DONE, "done", "Done" },
     93 };
     94 #define N_BOOT_TO_STR (sizeof(boot_to_str_tab)/sizeof(boot_to_str_tab[0]))
     95 
     96 /** Convert the name of a bootstrapping phase <b>s</b> into strings
     97 * <b>tag</b> and <b>summary</b> suitable for display by the controller. */
     98 static int
     99 bootstrap_status_to_string(bootstrap_status_t s, const char **tag,
    100                           const char **summary)
    101 {
    102  for (size_t i = 0; i < N_BOOT_TO_STR; i++) {
    103    if (s == boot_to_str_tab[i].status) {
    104      *tag = boot_to_str_tab[i].tag;
    105      *summary = boot_to_str_tab[i].summary;
    106      return 0;
    107    }
    108  }
    109 
    110  *tag = *summary = "unknown";
    111  return -1;
    112 }
    113 
    114 /** What percentage through the bootstrap process are we? We remember
    115 * this so we can avoid sending redundant bootstrap status events, and
    116 * so we can guess context for the bootstrap messages which are
    117 * ambiguous. It starts at 'undef', but gets set to 'starting' while
    118 * Tor initializes. */
    119 static int bootstrap_percent = BOOTSTRAP_STATUS_UNDEF;
    120 
    121 /** Like bootstrap_percent, but only takes on the enumerated values in
    122 * bootstrap_status_t.
    123 */
    124 static int bootstrap_phase = BOOTSTRAP_STATUS_UNDEF;
    125 
    126 /** As bootstrap_percent, but holds the bootstrapping level at which we last
    127 * logged a NOTICE-level message. We use this, plus BOOTSTRAP_PCT_INCREMENT,
    128 * to avoid flooding the log with a new message every time we get a few more
    129 * microdescriptors */
    130 static int notice_bootstrap_percent = 0;
    131 
    132 /** How many problems have we had getting to the next bootstrapping phase?
    133 * These include failure to establish a connection to a Tor relay,
    134 * failures to finish the TLS handshake, failures to validate the
    135 * consensus document, etc. */
    136 static int bootstrap_problems = 0;
    137 
    138 /** We only tell the controller once we've hit a threshold of problems
    139 * for the current phase. */
    140 #define BOOTSTRAP_PROBLEM_THRESHOLD 10
    141 
    142 /** When our bootstrapping progress level changes, but our bootstrapping
    143 * status has not advanced, we only log at NOTICE when we have made at least
    144 * this much progress.
    145 */
    146 #define BOOTSTRAP_PCT_INCREMENT 5
    147 
    148 /** Do the actual logging and notifications for
    149 * control_event_bootstrap().  Doesn't change any state beyond that.
    150 */
    151 static void
    152 control_event_bootstrap_core(int loglevel, bootstrap_status_t status,
    153                             int progress)
    154 {
    155  char buf[BOOTSTRAP_MSG_LEN];
    156  const char *tag, *summary;
    157 
    158  bootstrap_status_to_string(status, &tag, &summary);
    159  /* Locally reset status if there's incremental progress */
    160  if (progress)
    161    status = progress;
    162 
    163  tor_log(loglevel, LD_CONTROL,
    164          "Bootstrapped %d%% (%s): %s", status, tag, summary);
    165  tor_snprintf(buf, sizeof(buf),
    166               "BOOTSTRAP PROGRESS=%d TAG=%s SUMMARY=\"%s\"",
    167               status, tag, summary);
    168  tor_snprintf(last_sent_bootstrap_message,
    169               sizeof(last_sent_bootstrap_message),
    170               "NOTICE %s", buf);
    171  control_event_client_status(LOG_NOTICE, "%s", buf);
    172 }
    173 
    174 int
    175 control_get_bootstrap_percent(void)
    176 {
    177  return bootstrap_percent;
    178 }
    179 
    180 /** Called when Tor has made progress at bootstrapping its directory
    181 * information and initial circuits.
    182 *
    183 * <b>status</b> is the new status, that is, what task we will be doing
    184 * next. <b>progress</b> is zero if we just started this task, else it
    185 * represents progress on the task.
    186 */
    187 void
    188 control_event_bootstrap(bootstrap_status_t status, int progress)
    189 {
    190  int loglevel = LOG_NOTICE;
    191 
    192  if (bootstrap_percent == BOOTSTRAP_STATUS_DONE)
    193    return; /* already bootstrapped; nothing to be done here. */
    194 
    195  if (status <= bootstrap_percent) {
    196    /* If there's no new progress, return early. */
    197    if (!progress || progress <= bootstrap_percent)
    198      return;
    199    /* Log at INFO if not enough progress happened. */
    200    if (progress < notice_bootstrap_percent + BOOTSTRAP_PCT_INCREMENT)
    201      loglevel = LOG_INFO;
    202  }
    203 
    204  control_event_bootstrap_core(loglevel, status, progress);
    205 
    206  if (status > bootstrap_percent) {
    207    bootstrap_phase = status; /* new milestone reached */
    208    bootstrap_percent = status;
    209  }
    210  if (progress > bootstrap_percent) {
    211    /* incremental progress within a milestone */
    212    bootstrap_percent = progress;
    213    bootstrap_problems = 0; /* Progress! Reset our problem counter. */
    214  }
    215  if (loglevel == LOG_NOTICE &&
    216      bootstrap_percent > notice_bootstrap_percent) {
    217    /* Remember that we gave a notice at this level. */
    218    notice_bootstrap_percent = bootstrap_percent;
    219  }
    220 }
    221 
    222 /** Flag whether we've opened an OR_CONN yet  */
    223 static int bootstrap_first_orconn = 0;
    224 
    225 /** Like bootstrap_phase, but for (possibly deferred) directory progress */
    226 static int bootstrap_dir_phase = BOOTSTRAP_STATUS_UNDEF;
    227 
    228 /** Like bootstrap_problems, but for (possibly deferred) directory progress  */
    229 static int bootstrap_dir_progress = BOOTSTRAP_STATUS_UNDEF;
    230 
    231 /** Defer directory info bootstrap events until we have successfully
    232 * completed our first connection to a router.  */
    233 void
    234 control_event_boot_dir(bootstrap_status_t status, int progress)
    235 {
    236  if (status > bootstrap_dir_progress) {
    237    bootstrap_dir_progress = status;
    238    bootstrap_dir_phase = status;
    239  }
    240  if (progress && progress >= bootstrap_dir_progress) {
    241    bootstrap_dir_progress = progress;
    242  }
    243 
    244  /* Don't report unless we have successfully opened at least one OR_CONN */
    245  if (!bootstrap_first_orconn)
    246    return;
    247 
    248  control_event_bootstrap(status, progress);
    249 }
    250 
    251 /** Set a flag to allow reporting of directory bootstrap progress.
    252 * (Code that reports completion of an OR_CONN calls this.)  Also,
    253 * report directory progress so far. */
    254 void
    255 control_event_boot_first_orconn(void)
    256 {
    257  bootstrap_first_orconn = 1;
    258  control_event_bootstrap(bootstrap_dir_phase, bootstrap_dir_progress);
    259 }
    260 
    261 /** Called when Tor has failed to make bootstrapping progress in a way
    262 * that indicates a problem. <b>warn</b> gives a human-readable hint
    263 * as to why, and <b>reason</b> provides a controller-facing short
    264 * tag.  <b>conn</b> is the connection that caused this problem and
    265 * can be NULL if a connection cannot be easily identified.
    266 */
    267 void
    268 control_event_bootstrap_problem(const char *warn, const char *reason,
    269                                const connection_t *conn, int dowarn)
    270 {
    271  int status = bootstrap_percent;
    272  const char *tag = "", *summary = "";
    273  char buf[BOOTSTRAP_MSG_LEN];
    274  const char *recommendation = "ignore";
    275  int severity;
    276  char *or_id = NULL, *hostaddr = NULL;
    277  const or_connection_t *or_conn = NULL;
    278 
    279  /* bootstrap_percent must not be in "undefined" state here. */
    280  tor_assert(status >= 0);
    281 
    282  if (bootstrap_percent == 100)
    283    return; /* already bootstrapped; nothing to be done here. */
    284 
    285  bootstrap_problems++;
    286 
    287  if (bootstrap_problems >= BOOTSTRAP_PROBLEM_THRESHOLD)
    288    dowarn = 1;
    289 
    290  /* Don't warn about our bootstrapping status if we are hibernating or
    291   * shutting down. */
    292  if (we_are_hibernating())
    293    dowarn = 0;
    294 
    295  tor_assert(bootstrap_status_to_string(bootstrap_phase, &tag, &summary) == 0);
    296 
    297  severity = dowarn ? LOG_WARN : LOG_INFO;
    298 
    299  if (dowarn)
    300    recommendation = "warn";
    301 
    302  if (conn && conn->type == CONN_TYPE_OR) {
    303    /* XXX TO_OR_CONN can't deal with const */
    304    or_conn = CONST_TO_OR_CONN(conn);
    305    or_id = tor_strdup(hex_str(or_conn->identity_digest, DIGEST_LEN));
    306  } else {
    307    or_id = tor_strdup("?");
    308  }
    309 
    310  if (conn)
    311    tor_asprintf(&hostaddr, "%s:%d", conn->address, (int)conn->port);
    312  else
    313    hostaddr = tor_strdup("?");
    314 
    315  log_fn(severity,
    316         LD_CONTROL, "Problem bootstrapping. Stuck at %d%% (%s): %s. (%s; %s; "
    317         "count %d; recommendation %s; host %s at %s)",
    318         status, tag, summary, warn, reason,
    319         bootstrap_problems, recommendation,
    320         or_id, hostaddr);
    321 
    322  connection_or_report_broken_states(severity, LD_HANDSHAKE);
    323 
    324  tor_snprintf(buf, sizeof(buf),
    325      "BOOTSTRAP PROGRESS=%d TAG=%s SUMMARY=\"%s\" WARNING=\"%s\" REASON=%s "
    326      "COUNT=%d RECOMMENDATION=%s HOSTID=\"%s\" HOSTADDR=\"%s\"",
    327      bootstrap_percent, tag, summary, warn, reason, bootstrap_problems,
    328      recommendation,
    329      or_id, hostaddr);
    330 
    331  tor_snprintf(last_sent_bootstrap_message,
    332               sizeof(last_sent_bootstrap_message),
    333               "WARN %s", buf);
    334  control_event_client_status(LOG_WARN, "%s", buf);
    335 
    336  tor_free(hostaddr);
    337  tor_free(or_id);
    338 }
    339 
    340 /** Called when Tor has failed to make bootstrapping progress in a way
    341 * that indicates a problem. <b>warn</b> gives a hint as to why, and
    342 * <b>reason</b> provides an "or_conn_end_reason" tag.  <b>or_conn</b>
    343 * is the connection that caused this problem.
    344 */
    345 MOCK_IMPL(void,
    346 control_event_bootstrap_prob_or, (const char *warn, int reason,
    347                                  or_connection_t *or_conn))
    348 {
    349  int dowarn = 0;
    350 
    351  if (! or_conn->potentially_used_for_bootstrapping) {
    352    /* We never decided that this channel was a good match for one of our
    353     * origin_circuit_t objects.  That means that we probably launched it
    354     * for somebody else, most likely in response to an EXTEND cell.
    355     *
    356     * Since EXTEND cells can contain arbitrarily broken descriptions of
    357     * relays, a failure on this connection here won't necessarily indicate a
    358     * bootstrapping problem.
    359     */
    360    return;
    361  }
    362 
    363  if (or_conn->have_noted_bootstrap_problem)
    364    return;
    365 
    366  or_conn->have_noted_bootstrap_problem = 1;
    367 
    368  if (reason == END_OR_CONN_REASON_NO_ROUTE)
    369    dowarn = 1;
    370 
    371  /* If we are using bridges and all our OR connections are now
    372     closed, it means that we totally failed to connect to our
    373     bridges. Throw a warning. */
    374  if (get_options()->UseBridges && !any_other_active_or_conns(or_conn))
    375    dowarn = 1;
    376 
    377  control_event_bootstrap_problem(warn,
    378                                  orconn_end_reason_to_control_string(reason),
    379                                  TO_CONN(or_conn), dowarn);
    380 }
    381 
    382 /** Return a copy of the last sent bootstrap message. */
    383 char *
    384 control_event_boot_last_msg(void)
    385 {
    386  return tor_strdup(last_sent_bootstrap_message);
    387 }
    388 
    389 /** Reset bootstrap tracking state. */
    390 void
    391 control_event_bootstrap_reset(void)
    392 {
    393  bootstrap_percent = BOOTSTRAP_STATUS_UNDEF;
    394  bootstrap_phase = BOOTSTRAP_STATUS_UNDEF;
    395  notice_bootstrap_percent = 0;
    396  bootstrap_problems = 0;
    397  bootstrap_first_orconn = 0;
    398  bootstrap_dir_progress = BOOTSTRAP_STATUS_UNDEF;
    399  bootstrap_dir_phase = BOOTSTRAP_STATUS_UNDEF;
    400  memset(last_sent_bootstrap_message, 0, sizeof(last_sent_bootstrap_message));
    401 }