control_bootstrap.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
  2. * Copyright (c) 2007-2018, The Tor Project, Inc. */
  3. /* See LICENSE for licensing information */
  4. /**
  5. * \file control_bootstrap.c
  6. * \brief Provide bootstrap progress events for the control port.
  7. */
  8. #include "core/or/or.h"
  9. #include "app/config/config.h"
  10. #include "core/mainloop/connection.h"
  11. #include "core/or/connection_or.h"
  12. #include "core/or/connection_st.h"
  13. #include "core/or/or_connection_st.h"
  14. #include "core/or/reasons.h"
  15. #include "feature/control/control.h"
  16. #include "feature/hibernate/hibernate.h"
  17. #include "lib/malloc/malloc.h"
  18. /** A sufficiently large size to record the last bootstrap phase string. */
  19. #define BOOTSTRAP_MSG_LEN 1024
  20. /** What was the last bootstrap phase message we sent? We keep track
  21. * of this so we can respond to getinfo status/bootstrap-phase queries. */
  22. static char last_sent_bootstrap_message[BOOTSTRAP_MSG_LEN];
  23. /** Table to convert bootstrap statuses to strings. */
  24. static const struct {
  25. bootstrap_status_t status;
  26. const char *tag;
  27. const char *summary;
  28. } boot_to_str_tab[] = {
  29. { BOOTSTRAP_STATUS_UNDEF, "undef", "Undefined" },
  30. { BOOTSTRAP_STATUS_STARTING, "starting", "Starting" },
  31. { BOOTSTRAP_STATUS_CONN_DIR, "conn_dir", "Connecting to directory server" },
  32. { BOOTSTRAP_STATUS_HANDSHAKE, "status_handshake", "Finishing handshake" },
  33. { BOOTSTRAP_STATUS_HANDSHAKE_DIR, "handshake_dir",
  34. "Finishing handshake with directory server" },
  35. { BOOTSTRAP_STATUS_ONEHOP_CREATE, "onehop_create",
  36. "Establishing an encrypted directory connection" },
  37. { BOOTSTRAP_STATUS_REQUESTING_STATUS, "requesting_status",
  38. "Asking for networkstatus consensus" },
  39. { BOOTSTRAP_STATUS_LOADING_STATUS, "loading_status",
  40. "Loading networkstatus consensus" },
  41. { BOOTSTRAP_STATUS_LOADING_KEYS, "loading_keys",
  42. "Loading authority key certs" },
  43. { BOOTSTRAP_STATUS_REQUESTING_DESCRIPTORS, "requesting_descriptors",
  44. "Asking for relay descriptors" },
  45. { BOOTSTRAP_STATUS_LOADING_DESCRIPTORS, "loading_descriptors",
  46. "Loading relay descriptors" },
  47. { BOOTSTRAP_STATUS_CONN_OR, "conn_or", "Connecting to the Tor network" },
  48. { BOOTSTRAP_STATUS_HANDSHAKE_OR, "handshake_or",
  49. "Finishing handshake with first hop" },
  50. { BOOTSTRAP_STATUS_CIRCUIT_CREATE, "circuit_create",
  51. "Establishing a Tor circuit" },
  52. { BOOTSTRAP_STATUS_DONE, "done", "Done" },
  53. };
  54. #define N_BOOT_TO_STR (sizeof(boot_to_str_tab)/sizeof(boot_to_str_tab[0]))
  55. /** Convert the name of a bootstrapping phase <b>s</b> into strings
  56. * <b>tag</b> and <b>summary</b> suitable for display by the controller. */
  57. static int
  58. bootstrap_status_to_string(bootstrap_status_t s, const char **tag,
  59. const char **summary)
  60. {
  61. for (size_t i = 0; i < N_BOOT_TO_STR; i++) {
  62. if (s == boot_to_str_tab[i].status) {
  63. *tag = boot_to_str_tab[i].tag;
  64. *summary = boot_to_str_tab[i].summary;
  65. return 0;
  66. }
  67. }
  68. *tag = *summary = "unknown";
  69. return -1;
  70. }
  71. /** What percentage through the bootstrap process are we? We remember
  72. * this so we can avoid sending redundant bootstrap status events, and
  73. * so we can guess context for the bootstrap messages which are
  74. * ambiguous. It starts at 'undef', but gets set to 'starting' while
  75. * Tor initializes. */
  76. static int bootstrap_percent = BOOTSTRAP_STATUS_UNDEF;
  77. /** Like bootstrap_percent, but only takes on the enumerated values in
  78. * bootstrap_status_t.
  79. */
  80. static int bootstrap_phase = BOOTSTRAP_STATUS_UNDEF;
  81. /** As bootstrap_percent, but holds the bootstrapping level at which we last
  82. * logged a NOTICE-level message. We use this, plus BOOTSTRAP_PCT_INCREMENT,
  83. * to avoid flooding the log with a new message every time we get a few more
  84. * microdescriptors */
  85. static int notice_bootstrap_percent = 0;
  86. /** How many problems have we had getting to the next bootstrapping phase?
  87. * These include failure to establish a connection to a Tor relay,
  88. * failures to finish the TLS handshake, failures to validate the
  89. * consensus document, etc. */
  90. static int bootstrap_problems = 0;
  91. /** We only tell the controller once we've hit a threshold of problems
  92. * for the current phase. */
  93. #define BOOTSTRAP_PROBLEM_THRESHOLD 10
  94. /** When our bootstrapping progress level changes, but our bootstrapping
  95. * status has not advanced, we only log at NOTICE when we have made at least
  96. * this much progress.
  97. */
  98. #define BOOTSTRAP_PCT_INCREMENT 5
  99. /** Do the actual logging and notifications for
  100. * control_event_bootstrap(). Doesn't change any state beyond that.
  101. */
  102. static void
  103. control_event_bootstrap_core(int loglevel, bootstrap_status_t status,
  104. int progress)
  105. {
  106. char buf[BOOTSTRAP_MSG_LEN];
  107. const char *tag, *summary;
  108. bootstrap_status_to_string(status, &tag, &summary);
  109. /* Locally reset status if there's incremental progress */
  110. if (progress)
  111. status = progress;
  112. tor_log(loglevel, LD_CONTROL,
  113. "Bootstrapped %d%% (%s): %s", status, tag, summary);
  114. tor_snprintf(buf, sizeof(buf),
  115. "BOOTSTRAP PROGRESS=%d TAG=%s SUMMARY=\"%s\"",
  116. status, tag, summary);
  117. tor_snprintf(last_sent_bootstrap_message,
  118. sizeof(last_sent_bootstrap_message),
  119. "NOTICE %s", buf);
  120. control_event_client_status(LOG_NOTICE, "%s", buf);
  121. }
  122. /** Called when Tor has made progress at bootstrapping its directory
  123. * information and initial circuits.
  124. *
  125. * <b>status</b> is the new status, that is, what task we will be doing
  126. * next. <b>progress</b> is zero if we just started this task, else it
  127. * represents progress on the task.
  128. */
  129. void
  130. control_event_bootstrap(bootstrap_status_t status, int progress)
  131. {
  132. int loglevel = LOG_NOTICE;
  133. if (bootstrap_percent == BOOTSTRAP_STATUS_DONE)
  134. return; /* already bootstrapped; nothing to be done here. */
  135. /* special case for handshaking status, since our TLS handshaking code
  136. * can't distinguish what the connection is going to be for. */
  137. if (status == BOOTSTRAP_STATUS_HANDSHAKE) {
  138. if (bootstrap_percent < BOOTSTRAP_STATUS_CONN_OR) {
  139. status = BOOTSTRAP_STATUS_HANDSHAKE_DIR;
  140. } else {
  141. status = BOOTSTRAP_STATUS_HANDSHAKE_OR;
  142. }
  143. }
  144. if (status <= bootstrap_percent) {
  145. /* If there's no new progress, return early. */
  146. if (!progress || progress <= bootstrap_percent)
  147. return;
  148. /* Log at INFO if not enough progress happened. */
  149. if (progress < notice_bootstrap_percent + BOOTSTRAP_PCT_INCREMENT)
  150. loglevel = LOG_INFO;
  151. }
  152. control_event_bootstrap_core(loglevel, status, progress);
  153. if (status > bootstrap_percent) {
  154. bootstrap_phase = status; /* new milestone reached */
  155. bootstrap_percent = status;
  156. }
  157. if (progress > bootstrap_percent) {
  158. /* incremental progress within a milestone */
  159. bootstrap_percent = progress;
  160. bootstrap_problems = 0; /* Progress! Reset our problem counter. */
  161. }
  162. if (loglevel == LOG_NOTICE &&
  163. bootstrap_percent > notice_bootstrap_percent) {
  164. /* Remember that we gave a notice at this level. */
  165. notice_bootstrap_percent = bootstrap_percent;
  166. }
  167. }
  168. /** Flag whether we've opened an OR_CONN yet */
  169. static int bootstrap_first_orconn = 0;
  170. /** Like bootstrap_phase, but for (possibly deferred) directory progress */
  171. static int bootstrap_dir_phase = BOOTSTRAP_STATUS_UNDEF;
  172. /** Like bootstrap_problems, but for (possibly deferred) directory progress */
  173. static int bootstrap_dir_progress = BOOTSTRAP_STATUS_UNDEF;
  174. /** Defer directory info bootstrap events until we have successfully
  175. * completed our first connection to a router. */
  176. void
  177. control_event_boot_dir(bootstrap_status_t status, int progress)
  178. {
  179. if (status > bootstrap_dir_progress) {
  180. bootstrap_dir_progress = status;
  181. bootstrap_dir_phase = status;
  182. }
  183. if (progress && progress >= bootstrap_dir_progress) {
  184. bootstrap_dir_progress = progress;
  185. }
  186. /* Don't report unless we have successfully opened at least one OR_CONN */
  187. if (!bootstrap_first_orconn)
  188. return;
  189. control_event_bootstrap(status, progress);
  190. }
  191. /** Set a flag to allow reporting of directory bootstrap progress.
  192. * (Code that reports completion of an OR_CONN calls this.) Also,
  193. * report directory progress so far. */
  194. void
  195. control_event_boot_first_orconn(void)
  196. {
  197. bootstrap_first_orconn = 1;
  198. control_event_bootstrap(bootstrap_dir_phase, bootstrap_dir_progress);
  199. }
  200. /** Called when Tor has failed to make bootstrapping progress in a way
  201. * that indicates a problem. <b>warn</b> gives a human-readable hint
  202. * as to why, and <b>reason</b> provides a controller-facing short
  203. * tag. <b>conn</b> is the connection that caused this problem and
  204. * can be NULL if a connection cannot be easily identified.
  205. */
  206. void
  207. control_event_bootstrap_problem(const char *warn, const char *reason,
  208. const connection_t *conn, int dowarn)
  209. {
  210. int status = bootstrap_percent;
  211. const char *tag = "", *summary = "";
  212. char buf[BOOTSTRAP_MSG_LEN];
  213. const char *recommendation = "ignore";
  214. int severity;
  215. char *or_id = NULL, *hostaddr = NULL;
  216. or_connection_t *or_conn = NULL;
  217. /* bootstrap_percent must not be in "undefined" state here. */
  218. tor_assert(status >= 0);
  219. if (bootstrap_percent == 100)
  220. return; /* already bootstrapped; nothing to be done here. */
  221. bootstrap_problems++;
  222. if (bootstrap_problems >= BOOTSTRAP_PROBLEM_THRESHOLD)
  223. dowarn = 1;
  224. /* Don't warn about our bootstrapping status if we are hibernating or
  225. * shutting down. */
  226. if (we_are_hibernating())
  227. dowarn = 0;
  228. tor_assert(bootstrap_status_to_string(bootstrap_phase, &tag, &summary) == 0);
  229. severity = dowarn ? LOG_WARN : LOG_INFO;
  230. if (dowarn)
  231. recommendation = "warn";
  232. if (conn && conn->type == CONN_TYPE_OR) {
  233. /* XXX TO_OR_CONN can't deal with const */
  234. or_conn = TO_OR_CONN((connection_t *)conn);
  235. or_id = tor_strdup(hex_str(or_conn->identity_digest, DIGEST_LEN));
  236. } else {
  237. or_id = tor_strdup("?");
  238. }
  239. if (conn)
  240. tor_asprintf(&hostaddr, "%s:%d", conn->address, (int)conn->port);
  241. else
  242. hostaddr = tor_strdup("?");
  243. log_fn(severity,
  244. LD_CONTROL, "Problem bootstrapping. Stuck at %d%% (%s): %s. (%s; %s; "
  245. "count %d; recommendation %s; host %s at %s)",
  246. status, tag, summary, warn, reason,
  247. bootstrap_problems, recommendation,
  248. or_id, hostaddr);
  249. connection_or_report_broken_states(severity, LD_HANDSHAKE);
  250. tor_snprintf(buf, sizeof(buf),
  251. "BOOTSTRAP PROGRESS=%d TAG=%s SUMMARY=\"%s\" WARNING=\"%s\" REASON=%s "
  252. "COUNT=%d RECOMMENDATION=%s HOSTID=\"%s\" HOSTADDR=\"%s\"",
  253. bootstrap_percent, tag, summary, warn, reason, bootstrap_problems,
  254. recommendation,
  255. or_id, hostaddr);
  256. tor_snprintf(last_sent_bootstrap_message,
  257. sizeof(last_sent_bootstrap_message),
  258. "WARN %s", buf);
  259. control_event_client_status(LOG_WARN, "%s", buf);
  260. tor_free(hostaddr);
  261. tor_free(or_id);
  262. }
  263. /** Called when Tor has failed to make bootstrapping progress in a way
  264. * that indicates a problem. <b>warn</b> gives a hint as to why, and
  265. * <b>reason</b> provides an "or_conn_end_reason" tag. <b>or_conn</b>
  266. * is the connection that caused this problem.
  267. */
  268. MOCK_IMPL(void,
  269. control_event_bootstrap_prob_or, (const char *warn, int reason,
  270. or_connection_t *or_conn))
  271. {
  272. int dowarn = 0;
  273. if (or_conn->have_noted_bootstrap_problem)
  274. return;
  275. or_conn->have_noted_bootstrap_problem = 1;
  276. if (reason == END_OR_CONN_REASON_NO_ROUTE)
  277. dowarn = 1;
  278. /* If we are using bridges and all our OR connections are now
  279. closed, it means that we totally failed to connect to our
  280. bridges. Throw a warning. */
  281. if (get_options()->UseBridges && !any_other_active_or_conns(or_conn))
  282. dowarn = 1;
  283. control_event_bootstrap_problem(warn,
  284. orconn_end_reason_to_control_string(reason),
  285. TO_CONN(or_conn), dowarn);
  286. }
  287. /** Return a copy of the last sent bootstrap message. */
  288. char *
  289. control_event_boot_last_msg(void)
  290. {
  291. return tor_strdup(last_sent_bootstrap_message);
  292. }
  293. /** Reset bootstrap tracking state. */
  294. void
  295. control_event_bootstrap_reset(void)
  296. {
  297. bootstrap_percent = BOOTSTRAP_STATUS_UNDEF;
  298. bootstrap_phase = BOOTSTRAP_STATUS_UNDEF;
  299. notice_bootstrap_percent = 0;
  300. bootstrap_problems = 0;
  301. bootstrap_first_orconn = 0;
  302. bootstrap_dir_progress = BOOTSTRAP_STATUS_UNDEF;
  303. bootstrap_dir_phase = BOOTSTRAP_STATUS_UNDEF;
  304. memset(last_sent_bootstrap_message, 0, sizeof(last_sent_bootstrap_message));
  305. }