LCOV - code coverage report
Current view: top level - app/config - statefile.c (source / functions) Hit Total Coverage
Test: lcov.info Lines: 160 298 53.7 %
Date: 2021-11-24 03:28:48 Functions: 17 21 81.0 %

          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 : }

Generated by: LCOV version 1.14