Line data Source code
1 : /* Copyright (c) 2001 Matej Pfajfar.
2 : * Copyright (c) 2001-2004, Roger Dingledine.
3 : * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
4 : * Copyright (c) 2007-2021, The Tor Project, Inc. */
5 : /* See LICENSE for licensing information */
6 :
7 : /**
8 : * \file statefile.c
9 : *
10 : * \brief Handles parsing and encoding the persistent 'state' file that carries
11 : * miscellaneous persistent state between Tor invocations.
12 : *
13 : * This 'state' file is a typed key-value store that allows multiple
14 : * entries for the same key. It follows the same metaformat as described
15 : * in confmgt.c, and uses the same code to read and write itself.
16 : *
17 : * The state file is most suitable for small values that don't change too
18 : * frequently. For values that become very large, we typically use a separate
19 : * file -- for example, see how we handle microdescriptors, by storing them in
20 : * a separate file with a journal.
21 : *
22 : * The current state is accessed via get_or_state(), which returns a singleton
23 : * or_state_t object. Functions that change it should call
24 : * or_state_mark_dirty() to ensure that it will get written to disk.
25 : *
26 : * The or_state_save() function additionally calls various functioens
27 : * throughout Tor that might want to flush more state to the the disk,
28 : * including some in rephist.c, entrynodes.c, circuitstats.c, hibernate.c.
29 : */
30 :
31 : #define STATEFILE_PRIVATE
32 : #include "core/or/or.h"
33 : #include "core/or/circuitstats.h"
34 : #include "app/config/config.h"
35 : #include "feature/relay/transport_config.h"
36 : #include "lib/confmgt/confmgt.h"
37 : #include "core/mainloop/mainloop.h"
38 : #include "core/mainloop/netstatus.h"
39 : #include "core/mainloop/connection.h"
40 : #include "feature/control/control_events.h"
41 : #include "feature/client/entrynodes.h"
42 : #include "feature/hibernate/hibernate.h"
43 : #include "feature/stats/bwhist.h"
44 : #include "feature/relay/router.h"
45 : #include "feature/relay/routermode.h"
46 : #include "lib/sandbox/sandbox.h"
47 : #include "app/config/statefile.h"
48 : #include "app/main/subsysmgr.h"
49 : #include "lib/encoding/confline.h"
50 : #include "lib/net/resolve.h"
51 : #include "lib/version/torversion.h"
52 :
53 : #include "app/config/or_state_st.h"
54 :
55 : #ifdef HAVE_UNISTD_H
56 : #include <unistd.h>
57 : #endif
58 :
59 : /** A list of state-file "abbreviations," for compatibility. */
60 : static config_abbrev_t state_abbrevs_[] = {
61 : { NULL, NULL, 0, 0},
62 : };
63 :
64 : /** A list of obsolete keys that we do not and should not preserve.
65 : *
66 : * We could just let these live in ExtraLines indefinitely, but they're
67 : * never going to be used again, and every version that used them
68 : * has been obsolete for a long time.
69 : * */
70 : static const char *obsolete_state_keys[] = {
71 : /* These were renamed in 0.1.1.11-alpha */
72 : "AccountingBytesReadInterval",
73 : "HelperNode",
74 : "HelperNodeDownSince",
75 : "HelperNodeUnlistedSince",
76 : "EntryNode",
77 : "HelperNodeDownSince",
78 : "EntryNodeUnlistedSince",
79 : /* These were replaced by "Guard" in 0.3.0.1-alpha. */
80 : "EntryGuard",
81 : "EntryGuardDownSince",
82 : "EntryGuardUnlistedSince",
83 : "EntryGuardAddedBy",
84 : "EntryGuardPathBias",
85 : "EntryGuardPathUseBias",
86 : /* This was replaced by OPE-based revision numbers in 0.3.5.1-alpha,
87 : * and was never actually used in a released version. */
88 : "HidServRevCounter",
89 :
90 : NULL,
91 : };
92 :
93 : /** dummy instance of or_state_t, used for type-checking its
94 : * members with CONF_CHECK_VAR_TYPE. */
95 : DUMMY_TYPECHECK_INSTANCE(or_state_t);
96 :
97 : #define VAR(varname,conftype,member,initvalue) \
98 : CONFIG_VAR_ETYPE(or_state_t, varname, conftype, member, 0, initvalue)
99 : #define V(member,conftype,initvalue) \
100 : VAR(#member, conftype, member, initvalue)
101 :
102 : /** Array of "state" variables saved to the ~/.tor/state file. */
103 : // clang-format off
104 : static const config_var_t state_vars_[] = {
105 : /* Remember to document these in state-contents.txt ! */
106 :
107 : V(AccountingBytesReadInInterval, MEMUNIT, NULL),
108 : V(AccountingBytesWrittenInInterval, MEMUNIT, NULL),
109 : V(AccountingExpectedUsage, MEMUNIT, NULL),
110 : V(AccountingIntervalStart, ISOTIME, NULL),
111 : V(AccountingSecondsActive, INTERVAL, NULL),
112 : V(AccountingSecondsToReachSoftLimit,INTERVAL, NULL),
113 : V(AccountingSoftLimitHitAt, ISOTIME, NULL),
114 : V(AccountingBytesAtSoftLimit, MEMUNIT, NULL),
115 :
116 : VAR("TransportProxy", LINELIST_S, TransportProxies, NULL),
117 : V(TransportProxies, LINELIST_V, NULL),
118 :
119 : V(BWHistoryReadEnds, ISOTIME, NULL),
120 : V(BWHistoryReadInterval, POSINT, "900"),
121 : V(BWHistoryReadValues, CSV, ""),
122 : V(BWHistoryReadMaxima, CSV, ""),
123 : V(BWHistoryWriteEnds, ISOTIME, NULL),
124 : V(BWHistoryWriteInterval, POSINT, "900"),
125 : V(BWHistoryWriteValues, CSV, ""),
126 : V(BWHistoryWriteMaxima, CSV, ""),
127 : V(BWHistoryIPv6ReadEnds, ISOTIME, NULL),
128 : V(BWHistoryIPv6ReadInterval, POSINT, "900"),
129 : V(BWHistoryIPv6ReadValues, CSV, ""),
130 : V(BWHistoryIPv6ReadMaxima, CSV, ""),
131 : V(BWHistoryIPv6WriteEnds, ISOTIME, NULL),
132 : V(BWHistoryIPv6WriteInterval, POSINT, "900"),
133 : V(BWHistoryIPv6WriteValues, CSV, ""),
134 : V(BWHistoryIPv6WriteMaxima, CSV, ""),
135 : V(BWHistoryDirReadEnds, ISOTIME, NULL),
136 : V(BWHistoryDirReadInterval, POSINT, "900"),
137 : V(BWHistoryDirReadValues, CSV, ""),
138 : V(BWHistoryDirReadMaxima, CSV, ""),
139 : V(BWHistoryDirWriteEnds, ISOTIME, NULL),
140 : V(BWHistoryDirWriteInterval, POSINT, "900"),
141 : V(BWHistoryDirWriteValues, CSV, ""),
142 : V(BWHistoryDirWriteMaxima, CSV, ""),
143 :
144 : V(Guard, LINELIST, NULL),
145 :
146 : V(TorVersion, STRING, NULL),
147 :
148 : V(LastRotatedOnionKey, ISOTIME, NULL),
149 : V(LastWritten, ISOTIME, NULL),
150 :
151 : V(TotalBuildTimes, POSINT, NULL),
152 : V(CircuitBuildAbandonedCount, POSINT, "0"),
153 : VAR("CircuitBuildTimeBin", LINELIST_S, BuildtimeHistogram, NULL),
154 : VAR("BuildtimeHistogram", LINELIST_V, BuildtimeHistogram, NULL),
155 :
156 : END_OF_CONFIG_VARS
157 : };
158 : // clang-format on
159 :
160 : #undef VAR
161 : #undef V
162 :
163 : static int or_state_validate(or_state_t *state, char **msg);
164 :
165 : static int or_state_validate_cb(const void *old_options,
166 : void *options, char **msg);
167 :
168 : /** Magic value for or_state_t. */
169 : #define OR_STATE_MAGIC 0x57A73f57
170 :
171 : /** "Extra" variable in the state that receives lines we can't parse. This
172 : * lets us preserve options from versions of Tor newer than us. */
173 : static struct_member_t state_extra_var = {
174 : .name = "__extra",
175 : .type = CONFIG_TYPE_LINELIST,
176 : .offset = offsetof(or_state_t, ExtraLines),
177 : };
178 :
179 : /** Configuration format for or_state_t. */
180 : static const config_format_t state_format = {
181 : .size = sizeof(or_state_t),
182 : .magic = {
183 : "or_state_t",
184 : OR_STATE_MAGIC,
185 : offsetof(or_state_t, magic_),
186 : },
187 : .abbrevs = state_abbrevs_,
188 : .vars = state_vars_,
189 : .legacy_validate_fn = or_state_validate_cb,
190 : .extra = &state_extra_var,
191 : .has_config_suite = true,
192 : .config_suite_offset = offsetof(or_state_t, substates_),
193 : };
194 :
195 : /* A global configuration manager for state-file objects */
196 : static config_mgr_t *state_mgr = NULL;
197 :
198 : /** Return the configuration manager for state-file objects. */
199 : STATIC const config_mgr_t *
200 363 : get_state_mgr(void)
201 : {
202 363 : if (PREDICT_UNLIKELY(state_mgr == NULL)) {
203 113 : state_mgr = config_mgr_new(&state_format);
204 113 : int rv = subsystems_register_state_formats(state_mgr);
205 113 : tor_assert(rv == 0);
206 113 : config_mgr_freeze(state_mgr);
207 : }
208 363 : return state_mgr;
209 : }
210 :
211 : #define CHECK_STATE_MAGIC(s) STMT_BEGIN \
212 : config_check_toplevel_magic(get_state_mgr(), (s)); \
213 : STMT_END
214 :
215 : /** Persistent serialized state. */
216 : static or_state_t *global_state = NULL;
217 :
218 : /** Return the persistent state struct for this Tor. */
219 8 : MOCK_IMPL(or_state_t *,
220 : get_or_state, (void))
221 : {
222 8 : tor_assert(global_state);
223 8 : return global_state;
224 : }
225 :
226 : /** Return true iff we have loaded the global state for this Tor */
227 : int
228 213 : or_state_loaded(void)
229 : {
230 213 : return global_state != NULL;
231 : }
232 :
233 : /** Return true if <b>line</b> is a valid state TransportProxy line.
234 : * Return false otherwise. */
235 : static int
236 0 : state_transport_line_is_valid(const char *line)
237 : {
238 0 : smartlist_t *items = NULL;
239 0 : char *addrport=NULL;
240 0 : tor_addr_t addr;
241 0 : uint16_t port = 0;
242 0 : int r;
243 :
244 0 : items = smartlist_new();
245 0 : smartlist_split_string(items, line, NULL,
246 : SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1);
247 :
248 0 : if (smartlist_len(items) != 2) {
249 0 : log_warn(LD_CONFIG, "state: Not enough arguments in TransportProxy line.");
250 0 : goto err;
251 : }
252 :
253 0 : addrport = smartlist_get(items, 1);
254 0 : if (tor_addr_port_lookup(addrport, &addr, &port) < 0) {
255 0 : log_warn(LD_CONFIG, "state: Could not parse addrport.");
256 0 : goto err;
257 : }
258 :
259 0 : if (!port) {
260 0 : log_warn(LD_CONFIG, "state: Transport line did not contain port.");
261 0 : goto err;
262 : }
263 :
264 0 : r = 1;
265 0 : goto done;
266 :
267 : err:
268 : r = 0;
269 :
270 0 : done:
271 0 : SMARTLIST_FOREACH(items, char*, s, tor_free(s));
272 0 : smartlist_free(items);
273 0 : return r;
274 : }
275 :
276 : /** Return 0 if all TransportProxy lines in <b>state</b> are well
277 : * formed. Otherwise, return -1. */
278 : static int
279 8 : validate_transports_in_state(or_state_t *state)
280 : {
281 8 : int broken = 0;
282 8 : config_line_t *line;
283 :
284 8 : for (line = state->TransportProxies ; line ; line = line->next) {
285 0 : tor_assert(!strcmp(line->key, "TransportProxy"));
286 0 : if (!state_transport_line_is_valid(line->value))
287 0 : broken = 1;
288 : }
289 :
290 8 : if (broken)
291 0 : log_warn(LD_CONFIG, "state: State file seems to be broken.");
292 :
293 8 : return 0;
294 : }
295 :
296 : /** Return 0 if every setting in <b>state</b> is reasonable, and a
297 : * permissible transition from <b>old_state</b>. Else warn and return -1.
298 : * Should have no side effects, except for normalizing the contents of
299 : * <b>state</b>.
300 : */
301 : static int
302 4 : or_state_validate(or_state_t *state, char **msg)
303 : {
304 4 : return config_validate(get_state_mgr(), NULL, state, msg);
305 : }
306 :
307 : /**
308 : * Legacy validation/normalization callback for or_state_t. See
309 : * legacy_validate_fn_t for more information.
310 : */
311 : static int
312 8 : or_state_validate_cb(const void *old_state, void *state_, char **msg)
313 : {
314 : /* There is not a meaningful concept of a state-to-state transition,
315 : * since we do not reload the state after we start. */
316 8 : (void) old_state;
317 8 : CHECK_STATE_MAGIC(state_);
318 :
319 8 : or_state_t *state = state_;
320 :
321 8 : if (entry_guards_parse_state(state, 0, msg)<0)
322 : return -1;
323 :
324 8 : if (validate_transports_in_state(state)<0)
325 0 : return -1;
326 :
327 : return 0;
328 : }
329 :
330 : /** Replace the current persistent state with <b>new_state</b> */
331 : static int
332 4 : or_state_set(or_state_t *new_state)
333 : {
334 4 : char *err = NULL;
335 4 : int ret = 0;
336 4 : tor_assert(new_state);
337 4 : config_free(get_state_mgr(), global_state);
338 4 : global_state = new_state;
339 4 : if (subsystems_set_state(get_state_mgr(), global_state) < 0) {
340 0 : ret = -1;
341 : }
342 4 : if (entry_guards_parse_state(global_state, 1, &err)<0) {
343 0 : log_warn(LD_GENERAL,"%s",err);
344 0 : tor_free(err);
345 0 : ret = -1;
346 : }
347 4 : if (bwhist_load_state(global_state, &err)<0) {
348 0 : log_warn(LD_GENERAL,"Unparseable bandwidth history state: %s",err);
349 0 : tor_free(err);
350 0 : ret = -1;
351 : }
352 4 : if (circuit_build_times_parse_state(
353 : get_circuit_build_times_mutable(),global_state) < 0) {
354 0 : ret = -1;
355 : }
356 :
357 4 : return ret;
358 : }
359 :
360 : /**
361 : * Save a broken state file to a backup location.
362 : */
363 : static void
364 0 : or_state_save_broken(char *fname)
365 : {
366 0 : int i, res;
367 0 : file_status_t status;
368 0 : char *fname2 = NULL;
369 0 : for (i = 0; i < 100; ++i) {
370 0 : tor_asprintf(&fname2, "%s.%d", fname, i);
371 0 : status = file_status(fname2);
372 0 : if (status == FN_NOENT)
373 : break;
374 0 : tor_free(fname2);
375 : }
376 0 : if (i == 100) {
377 0 : log_warn(LD_BUG, "Unable to parse state in \"%s\"; too many saved bad "
378 : "state files to move aside. Discarding the old state file.",
379 : fname);
380 0 : res = unlink(fname);
381 0 : if (res != 0) {
382 0 : log_warn(LD_FS,
383 : "Also couldn't discard old state file \"%s\" because "
384 : "unlink() failed: %s",
385 : fname, strerror(errno));
386 : }
387 : } else {
388 0 : log_warn(LD_BUG, "Unable to parse state in \"%s\". Moving it aside "
389 : "to \"%s\". This could be a bug in Tor; please tell "
390 : "the developers.", fname, fname2);
391 0 : if (tor_rename(fname, fname2) < 0) {//XXXX sandbox prohibits
392 0 : log_warn(LD_BUG, "Weirdly, I couldn't even move the state aside. The "
393 : "OS gave an error of %s", strerror(errno));
394 : }
395 : }
396 0 : tor_free(fname2);
397 0 : }
398 :
399 : STATIC or_state_t *
400 113 : or_state_new(void)
401 : {
402 113 : or_state_t *new_state = config_new(get_state_mgr());
403 113 : config_init(get_state_mgr(), new_state);
404 :
405 113 : return new_state;
406 : }
407 :
408 : /** Reload the persistent state from disk, generating a new state as needed.
409 : * Return 0 on success, less than 0 on failure.
410 : */
411 : int
412 4 : or_state_load(void)
413 : {
414 4 : or_state_t *new_state = NULL;
415 4 : char *contents = NULL, *fname;
416 4 : char *errmsg = NULL;
417 4 : int r = -1, badstate = 0;
418 :
419 4 : fname = get_datadir_fname("state");
420 4 : switch (file_status(fname)) {
421 0 : case FN_FILE:
422 0 : if (!(contents = read_file_to_str(fname, 0, NULL))) {
423 0 : log_warn(LD_FS, "Unable to read state file \"%s\"", fname);
424 0 : goto done;
425 : }
426 : break;
427 : /* treat empty state files as if the file doesn't exist, and generate
428 : * a new state file, overwriting the empty file in or_state_save() */
429 : case FN_NOENT:
430 : case FN_EMPTY:
431 : break;
432 0 : case FN_ERROR:
433 : case FN_DIR:
434 : default:
435 0 : log_warn(LD_GENERAL,"State file \"%s\" is not a file? Failing.", fname);
436 0 : goto done;
437 : }
438 4 : new_state = or_state_new();
439 4 : if (contents) {
440 0 : config_line_t *lines=NULL;
441 0 : int assign_retval;
442 0 : if (config_get_lines(contents, &lines, 0)<0)
443 0 : goto done;
444 0 : assign_retval = config_assign(get_state_mgr(), new_state,
445 : lines, 0, &errmsg);
446 0 : config_free_lines(lines);
447 0 : if (assign_retval<0)
448 0 : badstate = 1;
449 0 : if (errmsg) {
450 0 : log_warn(LD_GENERAL, "%s", errmsg);
451 0 : tor_free(errmsg);
452 : }
453 : }
454 :
455 4 : if (!badstate && or_state_validate(new_state, &errmsg) < 0)
456 0 : badstate = 1;
457 :
458 4 : if (errmsg) {
459 0 : log_warn(LD_GENERAL, "%s", errmsg);
460 0 : tor_free(errmsg);
461 : }
462 :
463 4 : if (badstate && !contents) {
464 0 : log_warn(LD_BUG, "Uh oh. We couldn't even validate our own default state."
465 : " This is a bug in Tor.");
466 0 : goto done;
467 4 : } else if (badstate && contents) {
468 0 : or_state_save_broken(fname);
469 :
470 0 : tor_free(contents);
471 0 : config_free(get_state_mgr(), new_state);
472 :
473 0 : new_state = or_state_new();
474 4 : } else if (contents) {
475 0 : log_info(LD_GENERAL, "Loaded state from \"%s\"", fname);
476 : /* Warn the user if their clock has been set backwards,
477 : * they could be tricked into using old consensuses */
478 0 : time_t apparent_skew = time(NULL) - new_state->LastWritten;
479 0 : if (apparent_skew < 0) {
480 : /* Initialize bootstrap event reporting because we might call
481 : * clock_skew_warning() before the bootstrap state is
482 : * initialized, causing an assertion failure. */
483 0 : control_event_bootstrap(BOOTSTRAP_STATUS_STARTING, 0);
484 0 : clock_skew_warning(NULL, (long)apparent_skew, 1, LD_GENERAL,
485 : "local state file", fname);
486 : }
487 : } else {
488 4 : log_info(LD_GENERAL, "Initialized state");
489 : }
490 4 : or_state_remove_obsolete_lines(&new_state->ExtraLines);
491 4 : if (or_state_set(new_state) == -1) {
492 0 : or_state_save_broken(fname);
493 : }
494 4 : new_state = NULL;
495 4 : if (!contents) {
496 4 : global_state->next_write = 0;
497 4 : or_state_save(time(NULL));
498 : }
499 : r = 0;
500 :
501 4 : done:
502 4 : tor_free(fname);
503 4 : tor_free(contents);
504 4 : if (new_state)
505 0 : config_free(get_state_mgr(), new_state);
506 :
507 4 : return r;
508 : }
509 :
510 : /** Remove from `extra_lines` every element whose key appears in
511 : * `obsolete_state_keys`. */
512 : STATIC void
513 7 : or_state_remove_obsolete_lines(config_line_t **extra_lines)
514 : {
515 : /* make a strmap for the obsolete state names, so we can have O(1)
516 : lookup. */
517 7 : strmap_t *bad_keys = strmap_new();
518 105 : for (unsigned i = 0; obsolete_state_keys[i] != NULL; ++i) {
519 98 : strmap_set_lc(bad_keys, obsolete_state_keys[i], (void*)"rmv");
520 : }
521 :
522 : config_line_t **line = extra_lines;
523 14 : while (*line) {
524 7 : if (strmap_get_lc(bad_keys, (*line)->key) != NULL) {
525 : /* This key is obsolete; remove it. */
526 5 : config_line_t *victim = *line;
527 5 : *line = (*line)->next;
528 :
529 5 : victim->next = NULL; // prevent double-free.
530 5 : config_free_lines(victim);
531 : } else {
532 : /* This is just an unrecognized key; keep it. */
533 2 : line = &(*line)->next;
534 : }
535 : }
536 :
537 7 : strmap_free(bad_keys, NULL);
538 7 : }
539 :
540 : /** Did the last time we tried to write the state file fail? If so, we
541 : * should consider disabling such features as preemptive circuit generation
542 : * to compute circuit-build-time. */
543 : static int last_state_file_write_failed = 0;
544 :
545 : /** Return whether the state file failed to write last time we tried. */
546 : int
547 189 : did_last_state_file_write_fail(void)
548 : {
549 189 : return last_state_file_write_failed;
550 : }
551 :
552 : /** If writing the state to disk fails, try again after this many seconds. */
553 : #define STATE_WRITE_RETRY_INTERVAL 3600
554 :
555 : /** If we're a relay, how often should we checkpoint our state file even
556 : * if nothing else dirties it? This will checkpoint ongoing stats like
557 : * bandwidth used, per-country user stats, etc. */
558 : #define STATE_RELAY_CHECKPOINT_INTERVAL (12*60*60)
559 :
560 : /** Write the persistent state to disk. Return 0 for success, <0 on failure. */
561 : int
562 4 : or_state_save(time_t now)
563 : {
564 4 : char *state, *contents;
565 4 : char tbuf[ISO_TIME_LEN+1];
566 4 : char *fname;
567 :
568 4 : tor_assert(global_state);
569 :
570 4 : if (global_state->next_write > now)
571 : return 0;
572 :
573 : /* Call everything else that might dirty the state even more, in order
574 : * to avoid redundant writes. */
575 4 : (void) subsystems_flush_state(get_state_mgr(), global_state);
576 4 : entry_guards_update_state(global_state);
577 4 : bwhist_update_state(global_state);
578 4 : circuit_build_times_update_state(get_circuit_build_times(), global_state);
579 :
580 4 : if (accounting_is_enabled(get_options()))
581 0 : accounting_run_housekeeping(now);
582 :
583 4 : global_state->LastWritten = now;
584 :
585 4 : tor_free(global_state->TorVersion);
586 4 : tor_asprintf(&global_state->TorVersion, "Tor %s", get_version());
587 :
588 4 : state = config_dump(get_state_mgr(), NULL, global_state, 1, 0);
589 4 : format_local_iso_time(tbuf, now);
590 4 : tor_asprintf(&contents,
591 : "# Tor state file last generated on %s local time\n"
592 : "# Other times below are in UTC\n"
593 : "# You *do not* need to edit this file.\n\n%s",
594 : tbuf, state);
595 4 : tor_free(state);
596 4 : fname = get_datadir_fname("state");
597 4 : if (write_str_to_file(fname, contents, 0)<0) {
598 0 : log_warn(LD_FS, "Unable to write state to file \"%s\"; "
599 : "will try again later", fname);
600 0 : last_state_file_write_failed = 1;
601 0 : tor_free(fname);
602 0 : tor_free(contents);
603 : /* Try again after STATE_WRITE_RETRY_INTERVAL (or sooner, if the state
604 : * changes sooner). */
605 0 : global_state->next_write = now + STATE_WRITE_RETRY_INTERVAL;
606 0 : return -1;
607 : }
608 :
609 4 : last_state_file_write_failed = 0;
610 4 : log_info(LD_GENERAL, "Saved state to \"%s\"", fname);
611 4 : tor_free(fname);
612 4 : tor_free(contents);
613 :
614 4 : if (server_mode(get_options()))
615 4 : global_state->next_write = now + STATE_RELAY_CHECKPOINT_INTERVAL;
616 : else
617 0 : global_state->next_write = TIME_MAX;
618 :
619 : return 0;
620 : }
621 :
622 : /** Return the config line for transport <b>transport</b> in the current state.
623 : * Return NULL if there is no config line for <b>transport</b>. */
624 : STATIC config_line_t *
625 6 : get_transport_in_state_by_name(const char *transport)
626 : {
627 6 : or_state_t *or_state = get_or_state();
628 6 : config_line_t *line;
629 6 : config_line_t *ret = NULL;
630 6 : smartlist_t *items = NULL;
631 :
632 16 : for (line = or_state->TransportProxies ; line ; line = line->next) {
633 11 : tor_assert(!strcmp(line->key, "TransportProxy"));
634 :
635 11 : items = smartlist_new();
636 11 : smartlist_split_string(items, line->value, NULL,
637 : SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1);
638 11 : if (smartlist_len(items) != 2) /* broken state */
639 0 : goto done;
640 :
641 11 : if (!strcmp(smartlist_get(items, 0), transport)) {
642 1 : ret = line;
643 1 : goto done;
644 : }
645 :
646 30 : SMARTLIST_FOREACH(items, char*, s, tor_free(s));
647 10 : smartlist_free(items);
648 10 : items = NULL;
649 : }
650 :
651 5 : done:
652 6 : if (items) {
653 3 : SMARTLIST_FOREACH(items, char*, s, tor_free(s));
654 1 : smartlist_free(items);
655 : }
656 6 : return ret;
657 : }
658 :
659 : /** Return string containing the address:port part of the
660 : * TransportProxy <b>line</b> for transport <b>transport</b>.
661 : * If the line is corrupted, return NULL. */
662 : static const char *
663 0 : get_transport_bindaddr(const char *line, const char *transport)
664 : {
665 0 : char *line_tmp = NULL;
666 :
667 0 : if (strlen(line) < strlen(transport) + 2) {
668 0 : goto broken_state;
669 : } else {
670 : /* line should start with the name of the transport and a space.
671 : (for example, "obfs2 127.0.0.1:47245") */
672 0 : tor_asprintf(&line_tmp, "%s ", transport);
673 0 : if (strcmpstart(line, line_tmp))
674 0 : goto broken_state;
675 :
676 0 : tor_free(line_tmp);
677 0 : return (line+strlen(transport)+1);
678 : }
679 :
680 0 : broken_state:
681 0 : tor_free(line_tmp);
682 0 : return NULL;
683 : }
684 :
685 : /** Return a string containing the address:port that a proxy transport
686 : * should bind on. The string is stored on the heap and must be freed
687 : * by the caller of this function. */
688 : char *
689 0 : get_stored_bindaddr_for_server_transport(const char *transport)
690 : {
691 0 : char *default_addrport = NULL;
692 0 : const char *stored_bindaddr = NULL;
693 0 : config_line_t *line = NULL;
694 :
695 : {
696 : /* See if the user explicitly asked for a specific listening
697 : address for this transport. */
698 0 : char *conf_bindaddr = pt_get_bindaddr_from_config(transport);
699 0 : if (conf_bindaddr)
700 : return conf_bindaddr;
701 : }
702 :
703 0 : line = get_transport_in_state_by_name(transport);
704 0 : if (!line) /* Found no references in state for this transport. */
705 0 : goto no_bindaddr_found;
706 :
707 0 : stored_bindaddr = get_transport_bindaddr(line->value, transport);
708 0 : if (stored_bindaddr) /* found stored bindaddr in state file. */
709 0 : return tor_strdup(stored_bindaddr);
710 :
711 0 : no_bindaddr_found:
712 : /** If we didn't find references for this pluggable transport in the
713 : state file, we should instruct the pluggable transport proxy to
714 : listen on INADDR_ANY on a random ephemeral port. */
715 0 : tor_asprintf(&default_addrport, "%s:%s", fmt_addr32(INADDR_ANY), "0");
716 0 : return default_addrport;
717 : }
718 :
719 : /** Save <b>transport</b> listening on <b>addr</b>:<b>port</b> to
720 : state */
721 : void
722 5 : save_transport_to_state(const char *transport,
723 : const tor_addr_t *addr, uint16_t port)
724 : {
725 5 : or_state_t *state = get_or_state();
726 :
727 5 : char *transport_addrport=NULL;
728 :
729 : /** find where to write on the state */
730 5 : config_line_t **next, *line;
731 :
732 : /* see if this transport is already stored in state */
733 5 : config_line_t *transport_line =
734 5 : get_transport_in_state_by_name(transport);
735 :
736 5 : if (transport_line) { /* if transport already exists in state... */
737 0 : const char *prev_bindaddr = /* get its addrport... */
738 0 : get_transport_bindaddr(transport_line->value, transport);
739 0 : transport_addrport = tor_strdup(fmt_addrport(addr, port));
740 :
741 : /* if transport in state has the same address as this one, life is good */
742 0 : if (!strcmp(prev_bindaddr, transport_addrport)) {
743 0 : log_info(LD_CONFIG, "Transport seems to have spawned on its usual "
744 : "address:port.");
745 0 : goto done;
746 : } else { /* if addrport in state is different than the one we got */
747 0 : log_info(LD_CONFIG, "Transport seems to have spawned on different "
748 : "address:port. Let's update the state file with the new "
749 : "address:port");
750 0 : tor_free(transport_line->value); /* free the old line */
751 : /* replace old addrport line with new line */
752 0 : tor_asprintf(&transport_line->value, "%s %s", transport,
753 : fmt_addrport(addr, port));
754 : }
755 : } else { /* never seen this one before; save it in state for next time */
756 5 : log_info(LD_CONFIG, "It's the first time we see this transport. "
757 : "Let's save its address:port");
758 5 : next = &state->TransportProxies;
759 : /* find the last TransportProxy line in the state and point 'next'
760 : right after it */
761 5 : line = state->TransportProxies;
762 15 : while (line) {
763 10 : next = &(line->next);
764 10 : line = line->next;
765 : }
766 :
767 : /* allocate space for the new line and fill it in */
768 5 : *next = line = tor_malloc_zero(sizeof(config_line_t));
769 5 : line->key = tor_strdup("TransportProxy");
770 5 : tor_asprintf(&line->value, "%s %s", transport, fmt_addrport(addr, port));
771 : }
772 :
773 5 : if (!get_options()->AvoidDiskWrites)
774 5 : or_state_mark_dirty(state, 0);
775 :
776 0 : done:
777 5 : tor_free(transport_addrport);
778 5 : }
779 :
780 : /** Change the next_write time of <b>state</b> to <b>when</b>, unless the
781 : * state is already scheduled to be written to disk earlier than <b>when</b>.
782 : */
783 : void
784 2150 : or_state_mark_dirty(or_state_t *state, time_t when)
785 : {
786 2150 : if (state->next_write > when) {
787 0 : state->next_write = when;
788 0 : reschedule_or_state_save();
789 : }
790 2150 : }
791 :
792 : STATIC void
793 339 : or_state_free_(or_state_t *state)
794 : {
795 339 : if (!state)
796 : return;
797 :
798 108 : config_free(get_state_mgr(), state);
799 : }
800 :
801 : void
802 235 : or_state_free_all(void)
803 : {
804 235 : or_state_free(global_state);
805 235 : global_state = NULL;
806 235 : config_mgr_free(state_mgr);
807 235 : }
|