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 *
get_state_mgr(void)200 get_state_mgr(void)
201 {
202   if (PREDICT_UNLIKELY(state_mgr == NULL)) {
203     state_mgr = config_mgr_new(&state_format);
204     int rv = subsystems_register_state_formats(state_mgr);
205     tor_assert(rv == 0);
206     config_mgr_freeze(state_mgr);
207   }
208   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 MOCK_IMPL(or_state_t *,
220 get_or_state, (void))
221 {
222   tor_assert(global_state);
223   return global_state;
224 }
225 
226 /** Return true iff we have loaded the global state for this Tor */
227 int
or_state_loaded(void)228 or_state_loaded(void)
229 {
230   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
state_transport_line_is_valid(const char * line)236 state_transport_line_is_valid(const char *line)
237 {
238   smartlist_t *items = NULL;
239   char *addrport=NULL;
240   tor_addr_t addr;
241   uint16_t port = 0;
242   int r;
243 
244   items = smartlist_new();
245   smartlist_split_string(items, line, NULL,
246                          SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1);
247 
248   if (smartlist_len(items) != 2) {
249     log_warn(LD_CONFIG, "state: Not enough arguments in TransportProxy line.");
250     goto err;
251   }
252 
253   addrport = smartlist_get(items, 1);
254   if (tor_addr_port_lookup(addrport, &addr, &port) < 0) {
255     log_warn(LD_CONFIG, "state: Could not parse addrport.");
256     goto err;
257   }
258 
259   if (!port) {
260     log_warn(LD_CONFIG, "state: Transport line did not contain port.");
261     goto err;
262   }
263 
264   r = 1;
265   goto done;
266 
267  err:
268   r = 0;
269 
270  done:
271   SMARTLIST_FOREACH(items, char*, s, tor_free(s));
272   smartlist_free(items);
273   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
validate_transports_in_state(or_state_t * state)279 validate_transports_in_state(or_state_t *state)
280 {
281   int broken = 0;
282   config_line_t *line;
283 
284   for (line = state->TransportProxies ; line ; line = line->next) {
285     tor_assert(!strcmp(line->key, "TransportProxy"));
286     if (!state_transport_line_is_valid(line->value))
287       broken = 1;
288   }
289 
290   if (broken)
291     log_warn(LD_CONFIG, "state: State file seems to be broken.");
292 
293   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
or_state_validate(or_state_t * state,char ** msg)302 or_state_validate(or_state_t *state, char **msg)
303 {
304   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
or_state_validate_cb(const void * old_state,void * state_,char ** msg)312 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   (void) old_state;
317   CHECK_STATE_MAGIC(state_);
318 
319   or_state_t *state = state_;
320 
321   if (entry_guards_parse_state(state, 0, msg)<0)
322     return -1;
323 
324   if (validate_transports_in_state(state)<0)
325     return -1;
326 
327   return 0;
328 }
329 
330 /** Replace the current persistent state with <b>new_state</b> */
331 static int
or_state_set(or_state_t * new_state)332 or_state_set(or_state_t *new_state)
333 {
334   char *err = NULL;
335   int ret = 0;
336   tor_assert(new_state);
337   config_free(get_state_mgr(), global_state);
338   global_state = new_state;
339   if (subsystems_set_state(get_state_mgr(), global_state) < 0) {
340     ret = -1;
341   }
342   if (entry_guards_parse_state(global_state, 1, &err)<0) {
343     log_warn(LD_GENERAL,"%s",err);
344     tor_free(err);
345     ret = -1;
346   }
347   if (bwhist_load_state(global_state, &err)<0) {
348     log_warn(LD_GENERAL,"Unparseable bandwidth history state: %s",err);
349     tor_free(err);
350     ret = -1;
351   }
352   if (circuit_build_times_parse_state(
353       get_circuit_build_times_mutable(),global_state) < 0) {
354     ret = -1;
355   }
356 
357   return ret;
358 }
359 
360 /**
361  * Save a broken state file to a backup location.
362  */
363 static void
or_state_save_broken(char * fname)364 or_state_save_broken(char *fname)
365 {
366   int i, res;
367   file_status_t status;
368   char *fname2 = NULL;
369   for (i = 0; i < 100; ++i) {
370     tor_asprintf(&fname2, "%s.%d", fname, i);
371     status = file_status(fname2);
372     if (status == FN_NOENT)
373       break;
374     tor_free(fname2);
375   }
376   if (i == 100) {
377     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     res = unlink(fname);
381     if (res != 0) {
382       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     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     if (tor_rename(fname, fname2) < 0) {//XXXX sandbox prohibits
392       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   tor_free(fname2);
397 }
398 
399 STATIC or_state_t *
or_state_new(void)400 or_state_new(void)
401 {
402   or_state_t *new_state = config_new(get_state_mgr());
403   config_init(get_state_mgr(), new_state);
404 
405   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
or_state_load(void)412 or_state_load(void)
413 {
414   or_state_t *new_state = NULL;
415   char *contents = NULL, *fname;
416   char *errmsg = NULL;
417   int r = -1, badstate = 0;
418 
419   fname = get_datadir_fname("state");
420   switch (file_status(fname)) {
421     case FN_FILE:
422       if (!(contents = read_file_to_str(fname, 0, NULL))) {
423         log_warn(LD_FS, "Unable to read state file \"%s\"", fname);
424         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     case FN_ERROR:
433     case FN_DIR:
434     default:
435       log_warn(LD_GENERAL,"State file \"%s\" is not a file? Failing.", fname);
436       goto done;
437   }
438   new_state = or_state_new();
439   if (contents) {
440     config_line_t *lines=NULL;
441     int assign_retval;
442     if (config_get_lines(contents, &lines, 0)<0)
443       goto done;
444     assign_retval = config_assign(get_state_mgr(), new_state,
445                                   lines, 0, &errmsg);
446     config_free_lines(lines);
447     if (assign_retval<0)
448       badstate = 1;
449     if (errmsg) {
450       log_warn(LD_GENERAL, "%s", errmsg);
451       tor_free(errmsg);
452     }
453   }
454 
455   if (!badstate && or_state_validate(new_state, &errmsg) < 0)
456     badstate = 1;
457 
458   if (errmsg) {
459     log_warn(LD_GENERAL, "%s", errmsg);
460     tor_free(errmsg);
461   }
462 
463   if (badstate && !contents) {
464     log_warn(LD_BUG, "Uh oh.  We couldn't even validate our own default state."
465              " This is a bug in Tor.");
466     goto done;
467   } else if (badstate && contents) {
468     or_state_save_broken(fname);
469 
470     tor_free(contents);
471     config_free(get_state_mgr(), new_state);
472 
473     new_state = or_state_new();
474   } else if (contents) {
475     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     time_t apparent_skew = time(NULL) - new_state->LastWritten;
479     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       control_event_bootstrap(BOOTSTRAP_STATUS_STARTING, 0);
484       clock_skew_warning(NULL, (long)apparent_skew, 1, LD_GENERAL,
485                          "local state file", fname);
486     }
487   } else {
488     log_info(LD_GENERAL, "Initialized state");
489   }
490   or_state_remove_obsolete_lines(&new_state->ExtraLines);
491   if (or_state_set(new_state) == -1) {
492     or_state_save_broken(fname);
493   }
494   new_state = NULL;
495   if (!contents) {
496     global_state->next_write = 0;
497     or_state_save(time(NULL));
498   }
499   r = 0;
500 
501  done:
502   tor_free(fname);
503   tor_free(contents);
504   if (new_state)
505     config_free(get_state_mgr(), new_state);
506 
507   return r;
508 }
509 
510 /** Remove from `extra_lines` every element whose key appears in
511  * `obsolete_state_keys`. */
512 STATIC void
or_state_remove_obsolete_lines(config_line_t ** extra_lines)513 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   strmap_t *bad_keys = strmap_new();
518   for (unsigned i = 0; obsolete_state_keys[i] != NULL; ++i) {
519     strmap_set_lc(bad_keys, obsolete_state_keys[i], (void*)"rmv");
520   }
521 
522   config_line_t **line = extra_lines;
523   while (*line) {
524     if (strmap_get_lc(bad_keys, (*line)->key) != NULL) {
525       /* This key is obsolete; remove it. */
526       config_line_t *victim = *line;
527       *line = (*line)->next;
528 
529       victim->next = NULL; // prevent double-free.
530       config_free_lines(victim);
531     } else {
532       /* This is just an unrecognized key; keep it. */
533       line = &(*line)->next;
534     }
535   }
536 
537   strmap_free(bad_keys, NULL);
538 }
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
did_last_state_file_write_fail(void)547 did_last_state_file_write_fail(void)
548 {
549   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
or_state_save(time_t now)562 or_state_save(time_t now)
563 {
564   char *state, *contents;
565   char tbuf[ISO_TIME_LEN+1];
566   char *fname;
567 
568   tor_assert(global_state);
569 
570   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   (void) subsystems_flush_state(get_state_mgr(), global_state);
576   entry_guards_update_state(global_state);
577   bwhist_update_state(global_state);
578   circuit_build_times_update_state(get_circuit_build_times(), global_state);
579 
580   if (accounting_is_enabled(get_options()))
581     accounting_run_housekeeping(now);
582 
583   global_state->LastWritten = now;
584 
585   tor_free(global_state->TorVersion);
586   tor_asprintf(&global_state->TorVersion, "Tor %s", get_version());
587 
588   state = config_dump(get_state_mgr(), NULL, global_state, 1, 0);
589   format_local_iso_time(tbuf, now);
590   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   tor_free(state);
596   fname = get_datadir_fname("state");
597   if (write_str_to_file(fname, contents, 0)<0) {
598     log_warn(LD_FS, "Unable to write state to file \"%s\"; "
599              "will try again later", fname);
600     last_state_file_write_failed = 1;
601     tor_free(fname);
602     tor_free(contents);
603     /* Try again after STATE_WRITE_RETRY_INTERVAL (or sooner, if the state
604      * changes sooner). */
605     global_state->next_write = now + STATE_WRITE_RETRY_INTERVAL;
606     return -1;
607   }
608 
609   last_state_file_write_failed = 0;
610   log_info(LD_GENERAL, "Saved state to \"%s\"", fname);
611   tor_free(fname);
612   tor_free(contents);
613 
614   if (server_mode(get_options()))
615     global_state->next_write = now + STATE_RELAY_CHECKPOINT_INTERVAL;
616   else
617     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 *
get_transport_in_state_by_name(const char * transport)625 get_transport_in_state_by_name(const char *transport)
626 {
627   or_state_t *or_state = get_or_state();
628   config_line_t *line;
629   config_line_t *ret = NULL;
630   smartlist_t *items = NULL;
631 
632   for (line = or_state->TransportProxies ; line ; line = line->next) {
633     tor_assert(!strcmp(line->key, "TransportProxy"));
634 
635     items = smartlist_new();
636     smartlist_split_string(items, line->value, NULL,
637                            SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1);
638     if (smartlist_len(items) != 2) /* broken state */
639       goto done;
640 
641     if (!strcmp(smartlist_get(items, 0), transport)) {
642       ret = line;
643       goto done;
644     }
645 
646     SMARTLIST_FOREACH(items, char*, s, tor_free(s));
647     smartlist_free(items);
648     items = NULL;
649   }
650 
651  done:
652   if (items) {
653     SMARTLIST_FOREACH(items, char*, s, tor_free(s));
654     smartlist_free(items);
655   }
656   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 *
get_transport_bindaddr(const char * line,const char * transport)663 get_transport_bindaddr(const char *line, const char *transport)
664 {
665   char *line_tmp = NULL;
666 
667   if (strlen(line) < strlen(transport) + 2) {
668     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     tor_asprintf(&line_tmp, "%s ", transport);
673     if (strcmpstart(line, line_tmp))
674       goto broken_state;
675 
676     tor_free(line_tmp);
677     return (line+strlen(transport)+1);
678   }
679 
680  broken_state:
681   tor_free(line_tmp);
682   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 *
get_stored_bindaddr_for_server_transport(const char * transport)689 get_stored_bindaddr_for_server_transport(const char *transport)
690 {
691   char *default_addrport = NULL;
692   const char *stored_bindaddr = NULL;
693   config_line_t *line = NULL;
694 
695   {
696     /* See if the user explicitly asked for a specific listening
697        address for this transport. */
698     char *conf_bindaddr = pt_get_bindaddr_from_config(transport);
699     if (conf_bindaddr)
700       return conf_bindaddr;
701   }
702 
703   line = get_transport_in_state_by_name(transport);
704   if (!line) /* Found no references in state for this transport. */
705     goto no_bindaddr_found;
706 
707   stored_bindaddr = get_transport_bindaddr(line->value, transport);
708   if (stored_bindaddr) /* found stored bindaddr in state file. */
709     return tor_strdup(stored_bindaddr);
710 
711  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   tor_asprintf(&default_addrport, "%s:%s", fmt_addr32(INADDR_ANY), "0");
716   return default_addrport;
717 }
718 
719 /** Save <b>transport</b> listening on <b>addr</b>:<b>port</b> to
720     state */
721 void
save_transport_to_state(const char * transport,const tor_addr_t * addr,uint16_t port)722 save_transport_to_state(const char *transport,
723                         const tor_addr_t *addr, uint16_t port)
724 {
725   or_state_t *state = get_or_state();
726 
727   char *transport_addrport=NULL;
728 
729   /** find where to write on the state */
730   config_line_t **next, *line;
731 
732   /* see if this transport is already stored in state */
733   config_line_t *transport_line =
734     get_transport_in_state_by_name(transport);
735 
736   if (transport_line) { /* if transport already exists in state... */
737     const char *prev_bindaddr = /* get its addrport... */
738       get_transport_bindaddr(transport_line->value, transport);
739     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     if (!strcmp(prev_bindaddr, transport_addrport)) {
743       log_info(LD_CONFIG, "Transport seems to have spawned on its usual "
744                "address:port.");
745       goto done;
746     } else { /* if addrport in state is different than the one we got */
747       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       tor_free(transport_line->value); /* free the old line */
751       /* replace old addrport line with new line */
752       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     log_info(LD_CONFIG, "It's the first time we see this transport. "
757              "Let's save its address:port");
758     next = &state->TransportProxies;
759     /* find the last TransportProxy line in the state and point 'next'
760        right after it  */
761     line = state->TransportProxies;
762     while (line) {
763       next = &(line->next);
764       line = line->next;
765     }
766 
767     /* allocate space for the new line and fill it in */
768     *next = line = tor_malloc_zero(sizeof(config_line_t));
769     line->key = tor_strdup("TransportProxy");
770     tor_asprintf(&line->value, "%s %s", transport, fmt_addrport(addr, port));
771   }
772 
773   if (!get_options()->AvoidDiskWrites)
774     or_state_mark_dirty(state, 0);
775 
776  done:
777   tor_free(transport_addrport);
778 }
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
or_state_mark_dirty(or_state_t * state,time_t when)784 or_state_mark_dirty(or_state_t *state, time_t when)
785 {
786   if (state->next_write > when) {
787     state->next_write = when;
788     reschedule_or_state_save();
789   }
790 }
791 
792 STATIC void
or_state_free_(or_state_t * state)793 or_state_free_(or_state_t *state)
794 {
795   if (!state)
796     return;
797 
798   config_free(get_state_mgr(), state);
799 }
800 
801 void
or_state_free_all(void)802 or_state_free_all(void)
803 {
804   or_state_free(global_state);
805   global_state = NULL;
806   config_mgr_free(state_mgr);
807 }
808