Coverage Report

Created: 2025-08-25 06:30

/src/tor/src/app/config/statefile.c
Line
Count
Source (jump to first uncovered line)
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
get_state_mgr(void)
201
0
{
202
0
  if (PREDICT_UNLIKELY(state_mgr == NULL)) {
203
0
    state_mgr = config_mgr_new(&state_format);
204
0
    int rv = subsystems_register_state_formats(state_mgr);
205
0
    tor_assert(rv == 0);
206
0
    config_mgr_freeze(state_mgr);
207
0
  }
208
0
  return state_mgr;
209
0
}
210
211
0
#define CHECK_STATE_MAGIC(s) STMT_BEGIN                        \
212
0
    config_check_toplevel_magic(get_state_mgr(), (s));         \
213
0
  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
0
{
222
0
  tor_assert(global_state);
223
0
  return global_state;
224
0
}
225
226
/** Return true iff we have loaded the global state for this Tor */
227
int
228
or_state_loaded(void)
229
0
{
230
0
  return global_state != NULL;
231
0
}
232
233
/** Return true if <b>line</b> is a valid state TransportProxy line.
234
 *  Return false otherwise. */
235
static int
236
state_transport_line_is_valid(const char *line)
237
0
{
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
0
                         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
0
  }
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
0
  }
258
259
0
  if (!port) {
260
0
    log_warn(LD_CONFIG, "state: Transport line did not contain port.");
261
0
    goto err;
262
0
  }
263
264
0
  r = 1;
265
0
  goto done;
266
267
0
 err:
268
0
  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
0
}
275
276
/** Return 0 if all TransportProxy lines in <b>state</b> are well
277
 *  formed. Otherwise, return -1. */
278
static int
279
validate_transports_in_state(or_state_t *state)
280
0
{
281
0
  int broken = 0;
282
0
  config_line_t *line;
283
284
0
  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
0
  }
289
290
0
  if (broken)
291
0
    log_warn(LD_CONFIG, "state: State file seems to be broken.");
292
293
0
  return 0;
294
0
}
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
or_state_validate(or_state_t *state, char **msg)
303
0
{
304
0
  return config_validate(get_state_mgr(), NULL, state, msg);
305
0
}
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
or_state_validate_cb(const void *old_state, void *state_, char **msg)
313
0
{
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
0
  (void) old_state;
317
0
  CHECK_STATE_MAGIC(state_);
318
319
0
  or_state_t *state = state_;
320
321
0
  if (entry_guards_parse_state(state, 0, msg)<0)
322
0
    return -1;
323
324
0
  if (validate_transports_in_state(state)<0)
325
0
    return -1;
326
327
0
  return 0;
328
0
}
329
330
/** Replace the current persistent state with <b>new_state</b> */
331
static int
332
or_state_set(or_state_t *new_state)
333
0
{
334
0
  char *err = NULL;
335
0
  int ret = 0;
336
0
  tor_assert(new_state);
337
0
  config_free(get_state_mgr(), global_state);
338
0
  global_state = new_state;
339
0
  if (subsystems_set_state(get_state_mgr(), global_state) < 0) {
340
0
    ret = -1;
341
0
  }
342
0
  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
0
  }
347
0
  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
0
  }
352
0
  if (circuit_build_times_parse_state(
353
0
      get_circuit_build_times_mutable(),global_state) < 0) {
354
0
    ret = -1;
355
0
  }
356
357
0
  return ret;
358
0
}
359
360
/**
361
 * Save a broken state file to a backup location.
362
 */
363
static void
364
or_state_save_broken(char *fname)
365
0
{
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
0
      break;
374
0
    tor_free(fname2);
375
0
  }
376
0
  if (i == 100) {
377
0
    log_warn(LD_BUG, "Unable to parse state in \"%s\"; too many saved bad "
378
0
             "state files to move aside. Discarding the old state file.",
379
0
             fname);
380
0
    res = unlink(fname);
381
0
    if (res != 0) {
382
0
      log_warn(LD_FS,
383
0
               "Also couldn't discard old state file \"%s\" because "
384
0
               "unlink() failed: %s",
385
0
               fname, strerror(errno));
386
0
    }
387
0
  } else {
388
0
    log_warn(LD_BUG, "Unable to parse state in \"%s\". Moving it aside "
389
0
             "to \"%s\".  This could be a bug in Tor; please tell "
390
0
             "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
0
               "OS gave an error of %s", strerror(errno));
394
0
    }
395
0
  }
396
0
  tor_free(fname2);
397
0
}
398
399
STATIC or_state_t *
400
or_state_new(void)
401
0
{
402
0
  or_state_t *new_state = config_new(get_state_mgr());
403
0
  config_init(get_state_mgr(), new_state);
404
405
0
  return new_state;
406
0
}
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
or_state_load(void)
413
0
{
414
0
  or_state_t *new_state = NULL;
415
0
  char *contents = NULL, *fname;
416
0
  char *errmsg = NULL;
417
0
  int r = -1, badstate = 0;
418
419
0
  fname = get_datadir_fname("state");
420
0
  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
0
      }
426
0
      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
0
    case FN_NOENT:
430
0
    case FN_EMPTY:
431
0
      break;
432
0
    case FN_ERROR:
433
0
    case FN_DIR:
434
0
    default:
435
0
      log_warn(LD_GENERAL,"State file \"%s\" is not a file? Failing.", fname);
436
0
      goto done;
437
0
  }
438
0
  new_state = or_state_new();
439
0
  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
0
                                  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
0
    }
453
0
  }
454
455
0
  if (!badstate && or_state_validate(new_state, &errmsg) < 0)
456
0
    badstate = 1;
457
458
0
  if (errmsg) {
459
0
    log_warn(LD_GENERAL, "%s", errmsg);
460
0
    tor_free(errmsg);
461
0
  }
462
463
0
  if (badstate && !contents) {
464
0
    log_warn(LD_BUG, "Uh oh.  We couldn't even validate our own default state."
465
0
             " This is a bug in Tor.");
466
0
    goto done;
467
0
  } 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
0
  } 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
0
                         "local state file", fname);
486
0
    }
487
0
  } else {
488
0
    log_info(LD_GENERAL, "Initialized state");
489
0
  }
490
0
  or_state_remove_obsolete_lines(&new_state->ExtraLines);
491
0
  if (or_state_set(new_state) == -1) {
492
0
    or_state_save_broken(fname);
493
0
  }
494
0
  new_state = NULL;
495
0
  if (!contents) {
496
0
    global_state->next_write = 0;
497
0
    or_state_save(time(NULL));
498
0
  }
499
0
  r = 0;
500
501
0
 done:
502
0
  tor_free(fname);
503
0
  tor_free(contents);
504
0
  if (new_state)
505
0
    config_free(get_state_mgr(), new_state);
506
507
0
  return r;
508
0
}
509
510
/** Remove from `extra_lines` every element whose key appears in
511
 * `obsolete_state_keys`. */
512
STATIC void
513
or_state_remove_obsolete_lines(config_line_t **extra_lines)
514
0
{
515
  /* make a strmap for the obsolete state names, so we can have O(1)
516
     lookup. */
517
0
  strmap_t *bad_keys = strmap_new();
518
0
  for (unsigned i = 0; obsolete_state_keys[i] != NULL; ++i) {
519
0
    strmap_set_lc(bad_keys, obsolete_state_keys[i], (void*)"rmv");
520
0
  }
521
522
0
  config_line_t **line = extra_lines;
523
0
  while (*line) {
524
0
    if (strmap_get_lc(bad_keys, (*line)->key) != NULL) {
525
      /* This key is obsolete; remove it. */
526
0
      config_line_t *victim = *line;
527
0
      *line = (*line)->next;
528
529
0
      victim->next = NULL; // prevent double-free.
530
0
      config_free_lines(victim);
531
0
    } else {
532
      /* This is just an unrecognized key; keep it. */
533
0
      line = &(*line)->next;
534
0
    }
535
0
  }
536
537
0
  strmap_free(bad_keys, NULL);
538
0
}
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
did_last_state_file_write_fail(void)
548
0
{
549
0
  return last_state_file_write_failed;
550
0
}
551
552
/** If writing the state to disk fails, try again after this many seconds. */
553
0
#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
0
#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
or_state_save(time_t now)
563
0
{
564
0
  char *state, *contents;
565
0
  char tbuf[ISO_TIME_LEN+1];
566
0
  char *fname;
567
568
0
  tor_assert(global_state);
569
570
0
  if (global_state->next_write > now)
571
0
    return 0;
572
573
  /* Call everything else that might dirty the state even more, in order
574
   * to avoid redundant writes. */
575
0
  (void) subsystems_flush_state(get_state_mgr(), global_state);
576
0
  entry_guards_update_state(global_state);
577
0
  bwhist_update_state(global_state);
578
0
  circuit_build_times_update_state(get_circuit_build_times(), global_state);
579
580
0
  if (accounting_is_enabled(get_options()))
581
0
    accounting_run_housekeeping(now);
582
583
0
  global_state->LastWritten = now;
584
585
0
  tor_free(global_state->TorVersion);
586
0
  tor_asprintf(&global_state->TorVersion, "Tor %s", get_version());
587
588
0
  state = config_dump(get_state_mgr(), NULL, global_state, 1, 0);
589
0
  format_local_iso_time(tbuf, now);
590
0
  tor_asprintf(&contents,
591
0
               "# Tor state file last generated on %s local time\n"
592
0
               "# Other times below are in UTC\n"
593
0
               "# You *do not* need to edit this file.\n\n%s",
594
0
               tbuf, state);
595
0
  tor_free(state);
596
0
  fname = get_datadir_fname("state");
597
0
  if (write_str_to_file(fname, contents, 0)<0) {
598
0
    log_warn(LD_FS, "Unable to write state to file \"%s\"; "
599
0
             "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
0
  }
608
609
0
  last_state_file_write_failed = 0;
610
0
  log_info(LD_GENERAL, "Saved state to \"%s\"", fname);
611
0
  tor_free(fname);
612
0
  tor_free(contents);
613
614
0
  if (server_mode(get_options()))
615
0
    global_state->next_write = now + STATE_RELAY_CHECKPOINT_INTERVAL;
616
0
  else
617
0
    global_state->next_write = TIME_MAX;
618
619
0
  return 0;
620
0
}
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
get_transport_in_state_by_name(const char *transport)
626
0
{
627
0
  or_state_t *or_state = get_or_state();
628
0
  config_line_t *line;
629
0
  config_line_t *ret = NULL;
630
0
  smartlist_t *items = NULL;
631
632
0
  for (line = or_state->TransportProxies ; line ; line = line->next) {
633
0
    tor_assert(!strcmp(line->key, "TransportProxy"));
634
635
0
    items = smartlist_new();
636
0
    smartlist_split_string(items, line->value, NULL,
637
0
                           SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1);
638
0
    if (smartlist_len(items) != 2) /* broken state */
639
0
      goto done;
640
641
0
    if (!strcmp(smartlist_get(items, 0), transport)) {
642
0
      ret = line;
643
0
      goto done;
644
0
    }
645
646
0
    SMARTLIST_FOREACH(items, char*, s, tor_free(s));
647
0
    smartlist_free(items);
648
0
    items = NULL;
649
0
  }
650
651
0
 done:
652
0
  if (items) {
653
0
    SMARTLIST_FOREACH(items, char*, s, tor_free(s));
654
0
    smartlist_free(items);
655
0
  }
656
0
  return ret;
657
0
}
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
get_transport_bindaddr(const char *line, const char *transport)
664
0
{
665
0
  char *line_tmp = NULL;
666
667
0
  if (strlen(line) < strlen(transport) + 2) {
668
0
    goto broken_state;
669
0
  } 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
0
  }
679
680
0
 broken_state:
681
0
  tor_free(line_tmp);
682
0
  return NULL;
683
0
}
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
get_stored_bindaddr_for_server_transport(const char *transport)
690
0
{
691
0
  char *default_addrport = NULL;
692
0
  const char *stored_bindaddr = NULL;
693
0
  config_line_t *line = NULL;
694
695
0
  {
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
0
      return conf_bindaddr;
701
0
  }
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
0
}
718
719
/** Save <b>transport</b> listening on <b>addr</b>:<b>port</b> to
720
    state */
721
void
722
save_transport_to_state(const char *transport,
723
                        const tor_addr_t *addr, uint16_t port)
724
0
{
725
0
  or_state_t *state = get_or_state();
726
727
0
  char *transport_addrport=NULL;
728
729
  /** find where to write on the state */
730
0
  config_line_t **next, *line;
731
732
  /* see if this transport is already stored in state */
733
0
  config_line_t *transport_line =
734
0
    get_transport_in_state_by_name(transport);
735
736
0
  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
0
               "address:port.");
745
0
      goto done;
746
0
    } 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
0
               "address:port. Let's update the state file with the new "
749
0
               "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
0
                   fmt_addrport(addr, port));
754
0
    }
755
0
  } else { /* never seen this one before; save it in state for next time */
756
0
    log_info(LD_CONFIG, "It's the first time we see this transport. "
757
0
             "Let's save its address:port");
758
0
    next = &state->TransportProxies;
759
    /* find the last TransportProxy line in the state and point 'next'
760
       right after it  */
761
0
    line = state->TransportProxies;
762
0
    while (line) {
763
0
      next = &(line->next);
764
0
      line = line->next;
765
0
    }
766
767
    /* allocate space for the new line and fill it in */
768
0
    *next = line = tor_malloc_zero(sizeof(config_line_t));
769
0
    line->key = tor_strdup("TransportProxy");
770
0
    tor_asprintf(&line->value, "%s %s", transport, fmt_addrport(addr, port));
771
0
  }
772
773
0
  if (!get_options()->AvoidDiskWrites)
774
0
    or_state_mark_dirty(state, 0);
775
776
0
 done:
777
0
  tor_free(transport_addrport);
778
0
}
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
or_state_mark_dirty(or_state_t *state, time_t when)
785
0
{
786
0
  if (state->next_write > when) {
787
0
    state->next_write = when;
788
0
    reschedule_or_state_save();
789
0
  }
790
0
}
791
792
STATIC void
793
or_state_free_(or_state_t *state)
794
0
{
795
0
  if (!state)
796
0
    return;
797
798
0
  config_free(get_state_mgr(), state);
799
0
}
800
801
void
802
or_state_free_all(void)
803
0
{
804
0
  or_state_free(global_state);
805
0
  global_state = NULL;
806
0
  config_mgr_free(state_mgr);
807
0
}