Tor 0.4.9.0-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-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"
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. */
29static 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. */
98static 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. */
119static int bootstrap_percent = BOOTSTRAP_STATUS_UNDEF;
120
121/** Like bootstrap_percent, but only takes on the enumerated values in
122 * bootstrap_status_t.
123 */
124static 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. */
136static 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 */
151static 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
174int
175control_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 */
187void
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. */
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 &&
217 /* Remember that we gave a notice at this level. */
219 }
220}
221
222/** Flag whether we've opened an OR_CONN yet */
224
225/** Like bootstrap_phase, but for (possibly deferred) directory progress */
226static int bootstrap_dir_phase = BOOTSTRAP_STATUS_UNDEF;
227
228/** Like bootstrap_problems, but for (possibly deferred) directory progress */
229static 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. */
233void
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 */
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. */
254void
256{
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 */
267void
268control_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
286
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
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
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
333 "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 */
345MOCK_IMPL(void,
346control_event_bootstrap_prob_or, (const char *warn, int reason,
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
379 TO_CONN(or_conn), dowarn);
380}
381
382/** Return a copy of the last sent bootstrap message. */
383char *
385{
386 return tor_strdup(last_sent_bootstrap_message);
387}
388
389/** Reset bootstrap tracking state. */
390void
392{
393 bootstrap_percent = BOOTSTRAP_STATUS_UNDEF;
394 bootstrap_phase = BOOTSTRAP_STATUS_UNDEF;
398 bootstrap_dir_progress = BOOTSTRAP_STATUS_UNDEF;
399 bootstrap_dir_phase = BOOTSTRAP_STATUS_UNDEF;
401}
const char * hex_str(const char *from, size_t fromlen)
Definition: binascii.c:34
const or_options_t * get_options(void)
Definition: config.c:944
Header file for config.c.
int any_other_active_or_conns(const or_connection_t *this_conn)
Definition: connection.c:5022
Header file for connection.c.
#define CONN_TYPE_OR
Definition: connection.h:44
void connection_or_report_broken_states(int severity, int domain)
const or_connection_t * CONST_TO_OR_CONN(const connection_t *c)
Header file for connection_or.c.
Base connection structure.
char * control_event_boot_last_msg(void)
static int bootstrap_percent
void control_event_bootstrap_reset(void)
#define BOOTSTRAP_MSG_LEN
static const struct @19 boot_to_str_tab[]
static int bootstrap_phase
static void control_event_bootstrap_core(int loglevel, bootstrap_status_t status, int progress)
static char last_sent_bootstrap_message[BOOTSTRAP_MSG_LEN]
void control_event_bootstrap_problem(const char *warn, const char *reason, const connection_t *conn, int dowarn)
void control_event_boot_dir(bootstrap_status_t status, int progress)
#define BOOTSTRAP_PROBLEM_THRESHOLD
void control_event_bootstrap(bootstrap_status_t status, int progress)
#define BOOTSTRAP_PCT_INCREMENT
void control_event_boot_first_orconn(void)
static int bootstrap_first_orconn
static int bootstrap_status_to_string(bootstrap_status_t s, const char **tag, const char **summary)
static int bootstrap_dir_phase
static int notice_bootstrap_percent
void control_event_bootstrap_prob_or(const char *warn, int reason, or_connection_t *or_conn)
static int bootstrap_problems
static int bootstrap_dir_progress
int control_event_client_status(int severity, const char *format,...)
Header file for control_events.c.
bootstrap_status_t
#define DIGEST_LEN
Definition: digest_sizes.h:20
int we_are_hibernating(void)
Definition: hibernate.c:937
Header file for hibernate.c.
void tor_log(int severity, log_domain_mask_t domain, const char *format,...)
Definition: log.c:591
#define log_fn(severity, domain, args,...)
Definition: log.h:283
#define LD_HANDSHAKE
Definition: log.h:101
#define LOG_NOTICE
Definition: log.h:50
#define LD_CONTROL
Definition: log.h:80
#define LOG_WARN
Definition: log.h:53
#define LOG_INFO
Definition: log.h:45
Headers for util_malloc.c.
#define tor_free(p)
Definition: malloc.h:56
Master header file for Tor-specific functionality.
#define TO_CONN(c)
Definition: or.h:612
OR connection structure.
int tor_asprintf(char **strp, const char *fmt,...)
Definition: printf.c:75
int tor_snprintf(char *str, size_t size, const char *format,...)
Definition: printf.c:27
const char * orconn_end_reason_to_control_string(int r)
Definition: reasons.c:225
Header file for reasons.c.
unsigned int type
Definition: connection_st.h:50
uint16_t port
unsigned int potentially_used_for_bootstrapping
char identity_digest[DIGEST_LEN]
unsigned int have_noted_bootstrap_problem
#define MOCK_IMPL(rv, funcname, arglist)
Definition: testsupport.h:133
#define tor_assert(expr)
Definition: util_bug.h:103