aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--changes/ticket401376
-rw-r--r--src/app/config/or_state_st.h8
-rw-r--r--src/app/config/statefile.c77
-rw-r--r--src/app/config/statefile.h1
-rw-r--r--src/test/include.am1
-rw-r--r--src/test/test.c1
-rw-r--r--src/test/test.h1
-rw-r--r--src/test/test_statefile.c56
8 files changed, 127 insertions, 24 deletions
diff --git a/changes/ticket40137 b/changes/ticket40137
new file mode 100644
index 0000000000..056f1bc4a5
--- /dev/null
+++ b/changes/ticket40137
@@ -0,0 +1,6 @@
+ o Minor features (state):
+ - When loading the state file, remove entries from the statefile that
+ have been obsolete for a long time. Ordinarily Tor preserves
+ unrecognized entries in order to keep forward-compatibility, but
+ these statefile entries have not actually been used in any release
+ since before the 0.3.5.x. Closes ticket 40137.
diff --git a/src/app/config/or_state_st.h b/src/app/config/or_state_st.h
index 31b7f8a983..6769ef7b87 100644
--- a/src/app/config/or_state_st.h
+++ b/src/app/config/or_state_st.h
@@ -38,17 +38,11 @@ struct or_state_t {
uint64_t AccountingBytesAtSoftLimit;
uint64_t AccountingExpectedUsage;
- /** A list of Entry Guard-related configuration lines. (pre-prop271) */
- struct config_line_t *EntryGuards;
-
- /** A list of guard-related configuration lines. (post-prop271) */
+ /** A list of guard-related configuration lines. */
struct config_line_t *Guard;
struct config_line_t *TransportProxies;
- /** Cached revision counters for active hidden services on this host */
- struct config_line_t *HidServRevCounter;
-
/** These fields hold information on the history of bandwidth usage for
* servers. The "Ends" fields hold the time when we last updated the
* bandwidth usage. The "Interval" fields hold the granularity, in seconds,
diff --git a/src/app/config/statefile.c b/src/app/config/statefile.c
index b25167d2ec..22b15fcf24 100644
--- a/src/app/config/statefile.c
+++ b/src/app/config/statefile.c
@@ -58,16 +58,38 @@
/** A list of state-file "abbreviations," for compatibility. */
static config_abbrev_t state_abbrevs_[] = {
- { "AccountingBytesReadInterval", "AccountingBytesReadInInterval", 0, 0 },
- { "HelperNode", "EntryGuard", 0, 0 },
- { "HelperNodeDownSince", "EntryGuardDownSince", 0, 0 },
- { "HelperNodeUnlistedSince", "EntryGuardUnlistedSince", 0, 0 },
- { "EntryNode", "EntryGuard", 0, 0 },
- { "EntryNodeDownSince", "EntryGuardDownSince", 0, 0 },
- { "EntryNodeUnlistedSince", "EntryGuardUnlistedSince", 0, 0 },
{ NULL, NULL, 0, 0},
};
+/** A list of obsolete keys that we do not and should not preserve.
+ *
+ * We could just let these live in ExtraLines indefinitely, but they're
+ * never going to be used again, and every version that used them
+ * has been obsolete for a long time.
+ * */
+static const char *obsolete_state_keys[] = {
+ /* These were renamed in 0.1.1.11-alpha */
+ "AccountingBytesReadInterval",
+ "HelperNode",
+ "HelperNodeDownSince",
+ "HelperNodeUnlistedSince",
+ "EntryNode",
+ "HelperNodeDownSince",
+ "EntryNodeUnlistedSince",
+ /* These were replaced by "Guard" in 0.3.0.1-alpha. */
+ "EntryGuard",
+ "EntryGuardDownSince",
+ "EntryGuardUnlistedSince",
+ "EntryGuardAddedBy",
+ "EntryGuardPathBias",
+ "EntryGuardPathUseBias",
+ /* This was replaced by OPE-based revision numbers in 0.3.5.1-alpha,
+ * and was never actually used in a released version. */
+ "HidServRevCounter",
+
+ NULL,
+};
+
/** dummy instance of or_state_t, used for type-checking its
* members with CONF_CHECK_VAR_TYPE. */
DUMMY_TYPECHECK_INSTANCE(or_state_t);
@@ -91,19 +113,9 @@ static const config_var_t state_vars_[] = {
V(AccountingSoftLimitHitAt, ISOTIME, NULL),
V(AccountingBytesAtSoftLimit, MEMUNIT, NULL),
- VAR("EntryGuard", LINELIST_S, EntryGuards, NULL),
- VAR("EntryGuardDownSince", LINELIST_S, EntryGuards, NULL),
- VAR("EntryGuardUnlistedSince", LINELIST_S, EntryGuards, NULL),
- VAR("EntryGuardAddedBy", LINELIST_S, EntryGuards, NULL),
- VAR("EntryGuardPathBias", LINELIST_S, EntryGuards, NULL),
- VAR("EntryGuardPathUseBias", LINELIST_S, EntryGuards, NULL),
- V(EntryGuards, LINELIST_V, NULL),
-
VAR("TransportProxy", LINELIST_S, TransportProxies, NULL),
V(TransportProxies, LINELIST_V, NULL),
- V(HidServRevCounter, LINELIST, NULL),
-
V(BWHistoryReadEnds, ISOTIME, NULL),
V(BWHistoryReadInterval, POSINT, "900"),
V(BWHistoryReadValues, CSV, ""),
@@ -475,6 +487,7 @@ or_state_load(void)
} else {
log_info(LD_GENERAL, "Initialized state");
}
+ or_state_remove_obsolete_lines(&new_state->ExtraLines);
if (or_state_set(new_state) == -1) {
or_state_save_broken(fname);
}
@@ -494,6 +507,36 @@ or_state_load(void)
return r;
}
+/** Remove from `extra_lines` every element whose key appears in
+ * `obsolete_state_keys`. */
+STATIC void
+or_state_remove_obsolete_lines(config_line_t **extra_lines)
+{
+ /* make a strmap for the obsolete state names, so we can have O(1)
+ lookup. */
+ strmap_t *bad_keys = strmap_new();
+ for (unsigned i = 0; obsolete_state_keys[i] != NULL; ++i) {
+ strmap_set_lc(bad_keys, obsolete_state_keys[i], (void*)"rmv");
+ }
+
+ config_line_t **line = extra_lines;
+ while (*line) {
+ if (strmap_get_lc(bad_keys, (*line)->key) != NULL) {
+ /* This key is obsolete; remove it. */
+ config_line_t *victim = *line;
+ *line = (*line)->next;
+
+ victim->next = NULL; // prevent double-free.
+ config_free_lines(victim);
+ } else {
+ /* This is just an unrecognized key; keep it. */
+ line = &(*line)->next;
+ }
+ }
+
+ strmap_free(bad_keys, NULL);
+}
+
/** Did the last time we tried to write the state file fail? If so, we
* should consider disabling such features as preemptive circuit generation
* to compute circuit-build-time. */
diff --git a/src/app/config/statefile.h b/src/app/config/statefile.h
index 98d9d2dda1..89b10560f3 100644
--- a/src/app/config/statefile.h
+++ b/src/app/config/statefile.h
@@ -33,6 +33,7 @@ STATIC void or_state_free_(or_state_t *state);
STATIC or_state_t *or_state_new(void);
struct config_mgr_t;
STATIC const struct config_mgr_t *get_state_mgr(void);
+STATIC void or_state_remove_obsolete_lines(struct config_line_t **extra_lines);
#endif /* defined(STATEFILE_PRIVATE) */
#endif /* !defined(TOR_STATEFILE_H) */
diff --git a/src/test/include.am b/src/test/include.am
index 215e423834..173f007fbf 100644
--- a/src/test/include.am
+++ b/src/test/include.am
@@ -235,6 +235,7 @@ src_test_test_SOURCES += \
src/test/test_sendme.c \
src/test/test_shared_random.c \
src/test/test_socks.c \
+ src/test/test_statefile.c \
src/test/test_stats.c \
src/test/test_status.c \
src/test/test_storagedir.c \
diff --git a/src/test/test.c b/src/test/test.c
index 38c8206eea..77aa6db975 100644
--- a/src/test/test.c
+++ b/src/test/test.c
@@ -770,6 +770,7 @@ struct testgroup_t testgroups[] = {
{ "sendme/", sendme_tests },
{ "shared-random/", sr_tests },
{ "socks/", socks_tests },
+ { "statefile/", statefile_tests },
{ "stats/", stats_tests },
{ "status/" , status_tests },
{ "storagedir/", storagedir_tests },
diff --git a/src/test/test.h b/src/test/test.h
index 71066db48e..bd3a4102f5 100644
--- a/src/test/test.h
+++ b/src/test/test.h
@@ -187,6 +187,7 @@ extern struct testcase_t scheduler_tests[];
extern struct testcase_t sendme_tests[];
extern struct testcase_t socks_tests[];
extern struct testcase_t sr_tests[];
+extern struct testcase_t statefile_tests[];
extern struct testcase_t stats_tests[];
extern struct testcase_t status_tests[];
extern struct testcase_t storagedir_tests[];
diff --git a/src/test/test_statefile.c b/src/test/test_statefile.c
new file mode 100644
index 0000000000..dc9ecfee3e
--- /dev/null
+++ b/src/test/test_statefile.c
@@ -0,0 +1,56 @@
+/* Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "orconfig.h"
+
+#define STATEFILE_PRIVATE
+
+#include "core/or/or.h"
+#include "lib/encoding/confline.h"
+#include "app/config/statefile.h"
+
+#include "test/test.h"
+
+static void
+test_statefile_remove_obsolete(void *arg)
+{
+ (void)arg;
+ config_line_t *inp = NULL;
+ /* try empty config */
+ or_state_remove_obsolete_lines(&inp);
+ tt_assert(!inp);
+
+ /* try removing every line */
+ config_line_append(&inp, "EntryGuard", "doesn't matter");
+ config_line_append(&inp, "HidServRevCounter", "ignore");
+ config_line_append(&inp, "hidservrevcounter", "foobar"); // note case
+ or_state_remove_obsolete_lines(&inp);
+ tt_assert(!inp);
+
+ /* Now try removing a subset of lines. */
+ config_line_append(&inp, "EntryGuard", "doesn't matter");
+ config_line_append(&inp, "Guard", "in use");
+ config_line_append(&inp, "HidServRevCounter", "ignore");
+ config_line_append(&inp, "TorVersion", "this test doesn't care");
+ or_state_remove_obsolete_lines(&inp);
+ tt_assert(inp);
+ tt_str_op(inp->key, OP_EQ, "Guard");
+ tt_str_op(inp->value, OP_EQ, "in use");
+ tt_assert(inp->next);
+ tt_str_op(inp->next->key, OP_EQ, "TorVersion");
+ tt_str_op(inp->next->value, OP_EQ, "this test doesn't care");
+ tt_assert(! inp->next->next);
+
+ done:
+ config_free_lines(inp);
+}
+
+#define T(name) \
+ { #name, test_statefile_##name, 0, NULL, NULL }
+
+struct testcase_t statefile_tests[] = {
+ T(remove_obsolete),
+ END_OF_TESTCASES
+};