Tor  0.4.3.1-alpha-dev
control_bootstrap.c
Go to the documentation of this file.
1 /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
2  * Copyright (c) 2007-2020, 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"
13 #include "core/or/connection_or.h"
14 #include "core/or/connection_st.h"
16 #include "core/or/reasons.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. */
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
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 */
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
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);
170  "NOTICE %s", buf);
172 }
173 
174 /** Called when Tor has made progress at bootstrapping its directory
175  * information and initial circuits.
176  *
177  * <b>status</b> is the new status, that is, what task we will be doing
178  * next. <b>progress</b> is zero if we just started this task, else it
179  * represents progress on the task.
180  */
181 void
183 {
184  int loglevel = LOG_NOTICE;
185 
186  if (bootstrap_percent == BOOTSTRAP_STATUS_DONE)
187  return; /* already bootstrapped; nothing to be done here. */
188 
189  if (status <= bootstrap_percent) {
190  /* If there's no new progress, return early. */
191  if (!progress || progress <= bootstrap_percent)
192  return;
193  /* Log at INFO if not enough progress happened. */
195  loglevel = LOG_INFO;
196  }
197 
198  control_event_bootstrap_core(loglevel, status, progress);
199 
200  if (status > bootstrap_percent) {
201  bootstrap_phase = status; /* new milestone reached */
202  bootstrap_percent = status;
203  }
204  if (progress > bootstrap_percent) {
205  /* incremental progress within a milestone */
206  bootstrap_percent = progress;
207  bootstrap_problems = 0; /* Progress! Reset our problem counter. */
208  }
209  if (loglevel == LOG_NOTICE &&
211  /* Remember that we gave a notice at this level. */
213  }
214 }
215 
216 /** Flag whether we've opened an OR_CONN yet */
217 static int bootstrap_first_orconn = 0;
218 
219 /** Like bootstrap_phase, but for (possibly deferred) directory progress */
220 static int bootstrap_dir_phase = BOOTSTRAP_STATUS_UNDEF;
221 
222 /** Like bootstrap_problems, but for (possibly deferred) directory progress */
223 static int bootstrap_dir_progress = BOOTSTRAP_STATUS_UNDEF;
224 
225 /** Defer directory info bootstrap events until we have successfully
226  * completed our first connection to a router. */
227 void
229 {
230  if (status > bootstrap_dir_progress) {
231  bootstrap_dir_progress = status;
232  bootstrap_dir_phase = status;
233  }
234  if (progress && progress >= bootstrap_dir_progress) {
235  bootstrap_dir_progress = progress;
236  }
237 
238  /* Don't report unless we have successfully opened at least one OR_CONN */
240  return;
241 
242  control_event_bootstrap(status, progress);
243 }
244 
245 /** Set a flag to allow reporting of directory bootstrap progress.
246  * (Code that reports completion of an OR_CONN calls this.) Also,
247  * report directory progress so far. */
248 void
250 {
253 }
254 
255 /** Called when Tor has failed to make bootstrapping progress in a way
256  * that indicates a problem. <b>warn</b> gives a human-readable hint
257  * as to why, and <b>reason</b> provides a controller-facing short
258  * tag. <b>conn</b> is the connection that caused this problem and
259  * can be NULL if a connection cannot be easily identified.
260  */
261 void
262 control_event_bootstrap_problem(const char *warn, const char *reason,
263  const connection_t *conn, int dowarn)
264 {
265  int status = bootstrap_percent;
266  const char *tag = "", *summary = "";
267  char buf[BOOTSTRAP_MSG_LEN];
268  const char *recommendation = "ignore";
269  int severity;
270  char *or_id = NULL, *hostaddr = NULL;
271  or_connection_t *or_conn = NULL;
272 
273  /* bootstrap_percent must not be in "undefined" state here. */
274  tor_assert(status >= 0);
275 
276  if (bootstrap_percent == 100)
277  return; /* already bootstrapped; nothing to be done here. */
278 
280 
282  dowarn = 1;
283 
284  /* Don't warn about our bootstrapping status if we are hibernating or
285  * shutting down. */
286  if (we_are_hibernating())
287  dowarn = 0;
288 
290 
291  severity = dowarn ? LOG_WARN : LOG_INFO;
292 
293  if (dowarn)
294  recommendation = "warn";
295 
296  if (conn && conn->type == CONN_TYPE_OR) {
297  /* XXX TO_OR_CONN can't deal with const */
298  or_conn = TO_OR_CONN((connection_t *)conn);
299  or_id = tor_strdup(hex_str(or_conn->identity_digest, DIGEST_LEN));
300  } else {
301  or_id = tor_strdup("?");
302  }
303 
304  if (conn)
305  tor_asprintf(&hostaddr, "%s:%d", conn->address, (int)conn->port);
306  else
307  hostaddr = tor_strdup("?");
308 
309  log_fn(severity,
310  LD_CONTROL, "Problem bootstrapping. Stuck at %d%% (%s): %s. (%s; %s; "
311  "count %d; recommendation %s; host %s at %s)",
312  status, tag, summary, warn, reason,
313  bootstrap_problems, recommendation,
314  or_id, hostaddr);
315 
317 
318  tor_snprintf(buf, sizeof(buf),
319  "BOOTSTRAP PROGRESS=%d TAG=%s SUMMARY=\"%s\" WARNING=\"%s\" REASON=%s "
320  "COUNT=%d RECOMMENDATION=%s HOSTID=\"%s\" HOSTADDR=\"%s\"",
321  bootstrap_percent, tag, summary, warn, reason, bootstrap_problems,
322  recommendation,
323  or_id, hostaddr);
324 
327  "WARN %s", buf);
329 
330  tor_free(hostaddr);
331  tor_free(or_id);
332 }
333 
334 /** Called when Tor has failed to make bootstrapping progress in a way
335  * that indicates a problem. <b>warn</b> gives a hint as to why, and
336  * <b>reason</b> provides an "or_conn_end_reason" tag. <b>or_conn</b>
337  * is the connection that caused this problem.
338  */
339 MOCK_IMPL(void,
340 control_event_bootstrap_prob_or, (const char *warn, int reason,
341  or_connection_t *or_conn))
342 {
343  int dowarn = 0;
344 
345  if (or_conn->have_noted_bootstrap_problem)
346  return;
347 
348  or_conn->have_noted_bootstrap_problem = 1;
349 
350  if (reason == END_OR_CONN_REASON_NO_ROUTE)
351  dowarn = 1;
352 
353  /* If we are using bridges and all our OR connections are now
354  closed, it means that we totally failed to connect to our
355  bridges. Throw a warning. */
356  if (get_options()->UseBridges && !any_other_active_or_conns(or_conn))
357  dowarn = 1;
358 
361  TO_CONN(or_conn), dowarn);
362 }
363 
364 /** Return a copy of the last sent bootstrap message. */
365 char *
367 {
368  return tor_strdup(last_sent_bootstrap_message);
369 }
370 
371 /** Reset bootstrap tracking state. */
372 void
374 {
375  bootstrap_percent = BOOTSTRAP_STATUS_UNDEF;
376  bootstrap_phase = BOOTSTRAP_STATUS_UNDEF;
378  bootstrap_problems = 0;
380  bootstrap_dir_progress = BOOTSTRAP_STATUS_UNDEF;
381  bootstrap_dir_phase = BOOTSTRAP_STATUS_UNDEF;
383 }
static int bootstrap_problems
static int bootstrap_percent
#define TO_CONN(c)
Definition: or.h:735
#define MOCK_IMPL(rv, funcname, arglist)
Definition: testsupport.h:133
Header file for connection.c.
static char last_sent_bootstrap_message[BOOTSTRAP_MSG_LEN]
void control_event_boot_dir(bootstrap_status_t status, int progress)
#define LOG_INFO
Definition: log.h:45
void tor_log(int severity, log_domain_mask_t domain, const char *format,...)
Definition: log.c:628
OR connection structure.
Header file for config.c.
#define CONN_TYPE_OR
Definition: connection.h:42
const or_options_t * get_options(void)
Definition: config.c:926
#define tor_assert(expr)
Definition: util_bug.h:102
#define tor_free(p)
Definition: malloc.h:52
#define LOG_NOTICE
Definition: log.h:50
void control_event_bootstrap_prob_or(const char *warn, int reason, or_connection_t *or_conn)
Headers for util_malloc.c.
or_connection_t * TO_OR_CONN(connection_t *c)
void connection_or_report_broken_states(int severity, int domain)
void control_event_bootstrap(bootstrap_status_t status, int progress)
Header file for hibernate.c.
#define LD_CONTROL
Definition: log.h:80
static int bootstrap_dir_progress
int tor_asprintf(char **strp, const char *fmt,...)
Definition: printf.c:75
Base connection structure.
#define DIGEST_LEN
Definition: digest_sizes.h:20
static const struct @14 boot_to_str_tab[]
char * control_event_boot_last_msg(void)
Master header file for Tor-specific functionality.
bootstrap_status_t
const char * hex_str(const char *from, size_t fromlen)
Definition: binascii.c:34
void control_event_bootstrap_reset(void)
#define LD_HANDSHAKE
Definition: log.h:101
#define LOG_WARN
Definition: log.h:53
#define BOOTSTRAP_PCT_INCREMENT
int control_event_client_status(int severity, const char *format,...)
unsigned int have_noted_bootstrap_problem
static void control_event_bootstrap_core(int loglevel, bootstrap_status_t status, int progress)
#define BOOTSTRAP_PROBLEM_THRESHOLD
unsigned int type
Definition: connection_st.h:50
int tor_snprintf(char *str, size_t size, const char *format,...)
Definition: printf.c:27
static int bootstrap_dir_phase
uint16_t port
void control_event_bootstrap_problem(const char *warn, const char *reason, const connection_t *conn, int dowarn)
void control_event_boot_first_orconn(void)
#define log_fn(severity, domain, args,...)
Definition: log.h:287
static int bootstrap_first_orconn
int we_are_hibernating(void)
Definition: hibernate.c:937
static int notice_bootstrap_percent
int any_other_active_or_conns(const or_connection_t *this_conn)
Definition: connection.c:4699
Header file for reasons.c.
Header file for connection_or.c.
static int bootstrap_phase
static int bootstrap_status_to_string(bootstrap_status_t s, const char **tag, const char **summary)
Header file for control_events.c.
#define BOOTSTRAP_MSG_LEN
const char * orconn_end_reason_to_control_string(int r)
Definition: reasons.c:225
char identity_digest[DIGEST_LEN]