summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/tor.1.txt6
-rw-r--r--src/or/config.c61
-rw-r--r--src/or/config.h2
-rw-r--r--src/or/or.h4
-rw-r--r--src/or/router.c4
-rw-r--r--src/test/test_options.c115
6 files changed, 186 insertions, 6 deletions
diff --git a/doc/tor.1.txt b/doc/tor.1.txt
index f173a97aa3..021353dcb0 100644
--- a/doc/tor.1.txt
+++ b/doc/tor.1.txt
@@ -1987,6 +1987,12 @@ if DirPort is non-zero):
except that port specifiers are ignored. Any address not matched by
some entry in the policy is accepted.
+[[DirCache]] **DirCache** **0**|**1**::
+ When this option is set, Tor caches all current directory documents and
+ accepts client requests for them. Setting DirPort is not required for this,
+ because clients connect via the ORPort by default. Setting either DirPort
+ or BridgeRelay and setting DirCache to 0 is not supported. (Default: 1)
+
DIRECTORY AUTHORITY SERVER OPTIONS
----------------------------------
diff --git a/src/or/config.c b/src/or/config.c
index 9ec47d2459..f9cab9f670 100644
--- a/src/or/config.c
+++ b/src/or/config.c
@@ -222,6 +222,7 @@ static config_var_t option_vars_[] = {
V(DirPortFrontPage, FILENAME, NULL),
VAR("DirReqStatistics", BOOL, DirReqStatistics_option, "1"),
VAR("DirAuthority", LINELIST, DirAuthorities, NULL),
+ V(DirCache, BOOL, "1"),
V(DirAuthorityFallbackRate, DOUBLE, "1.0"),
V(DisableAllSwap, BOOL, "0"),
V(DisableDebuggerAttachment, BOOL, "1"),
@@ -3457,6 +3458,24 @@ options_validate(or_options_t *old_options, or_options_t *options,
REJECT("AccountingRule must be 'sum' or 'max'");
}
+ if (options->DirPort_set && !options->DirCache) {
+ REJECT("DirPort configured but DirCache disabled. DirPort requires "
+ "DirCache.");
+ }
+
+ if (options->BridgeRelay && !options->DirCache) {
+ REJECT("We're a bridge but DirCache is disabled. BridgeRelay requires "
+ "DirCache.");
+ }
+
+ if (server_mode(options)) {
+ char *msg = NULL;
+ if (have_enough_mem_for_dircache(options, 0, &msg)) {
+ log_warn(LD_CONFIG, "%s", msg);
+ tor_free(msg);
+ }
+ }
+
if (options->HTTPProxy) { /* parse it now */
if (tor_addr_port_lookup(options->HTTPProxy,
&options->HTTPProxyAddr, &options->HTTPProxyPort) < 0)
@@ -4065,6 +4084,48 @@ compute_real_max_mem_in_queues(const uint64_t val, int log_guess)
}
}
+/* If we have less than 300 MB suggest disabling dircache */
+#define DIRCACHE_MIN_MB_BANDWIDTH 300
+#define DIRCACHE_MIN_BANDWIDTH (DIRCACHE_MIN_MB_BANDWIDTH*ONE_MEGABYTE)
+#define STRINGIFY(val) #val
+
+/** Create a warning message for emitting if we are a dircache but may not have
+ * enough system memory, or if we are not a dircache but probably should be.
+ * Return -1 when a message is returned in *msg*, else return 0. */
+STATIC int
+have_enough_mem_for_dircache(const or_options_t *options, size_t total_mem,
+ char **msg)
+{
+ *msg = NULL;
+ if (total_mem == 0) {
+ if (get_total_system_memory(&total_mem) < 0)
+ total_mem = options->MaxMemInQueues;
+ }
+ if (options->DirCache) {
+ if (total_mem < DIRCACHE_MIN_BANDWIDTH) {
+ if (options->BridgeRelay) {
+ *msg = strdup("Running a Bridge with less than "
+ STRINGIFY(DIRCACHE_MIN_MB_BANDWIDTH) " MB of memory is "
+ "not recommended.");
+ } else {
+ *msg = strdup("Being a directory cache (default) with less than "
+ STRINGIFY(DIRCACHE_MIN_MB_BANDWIDTH) " MB of memory is "
+ "not recommended and may consume most of the available "
+ "resources, consider disabling this functionality by "
+ "setting the DirCache option to 0.");
+ }
+ }
+ } else {
+ if (total_mem >= DIRCACHE_MIN_BANDWIDTH) {
+ *msg = strdup("DirCache is disabled and we are configured as a "
+ "relay. This may disqualify us from becoming a guard in the "
+ "future.");
+ }
+ }
+ return *msg == NULL ? 0 : -1;
+}
+#undef STRINGIFY
+
/** Helper: return true iff s1 and s2 are both NULL, or both non-NULL
* equal strings. */
static int
diff --git a/src/or/config.h b/src/or/config.h
index bfdd1694eb..6e08f9d178 100644
--- a/src/or/config.h
+++ b/src/or/config.h
@@ -158,6 +158,8 @@ STATIC int parse_dir_authority_line(const char *line,
dirinfo_type_t required_type,
int validate_only);
STATIC int parse_dir_fallback_line(const char *line, int validate_only);
+STATIC int have_enough_mem_for_dircache(const or_options_t *options,
+ size_t total_mem, char **msg);
#endif
#endif
diff --git a/src/or/or.h b/src/or/or.h
index 3cb1e7d7ef..89c539817f 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -3969,6 +3969,10 @@ typedef struct {
/** Should we fetch our dir info at the start of the consensus period? */
int FetchDirInfoExtraEarly;
+ int DirCache; /**< Cache all directory documents and accept requests via
+ * tunnelled dir conns from clients. If 1, enabled (default);
+ * If 0, disabled. */
+
char *VirtualAddrNetworkIPv4; /**< Address and mask to hand out for virtual
* MAPADDRESS requests for IPv4 addresses */
char *VirtualAddrNetworkIPv6; /**< Address and mask to hand out for virtual
diff --git a/src/or/router.c b/src/or/router.c
index 1927cfd38b..5e4f855410 100644
--- a/src/or/router.c
+++ b/src/or/router.c
@@ -1176,7 +1176,9 @@ router_should_be_directory_server(const or_options_t *options, int dir_port)
int
dir_server_mode(const or_options_t *options)
{
- return (server_mode(options) || options->DirPort_set) &&
+ if (!options->DirCache)
+ return 0;
+ return (server_mode(options) || options->DirPort_set) &&
router_should_be_directory_server(options, 0);
}
diff --git a/src/test/test_options.c b/src/test/test_options.c
index a8ebadb14b..7e47f33de6 100644
--- a/src/test/test_options.c
+++ b/src/test/test_options.c
@@ -69,22 +69,29 @@ clear_log_messages(void)
messages = NULL;
}
+#define setup_options(opt,dflt) \
+ do { \
+ opt = options_new(); \
+ opt->command = CMD_RUN_TOR; \
+ options_init(opt); \
+ \
+ dflt = config_dup(&options_format, opt); \
+ clear_log_messages(); \
+ } while (0)
+
static void
test_options_validate_impl(const char *configuration,
const char *expect_errmsg,
int expect_log_severity,
const char *expect_log)
{
- or_options_t *opt = options_new();
+ or_options_t *opt=NULL;
or_options_t *dflt;
config_line_t *cl=NULL;
char *msg=NULL;
int r;
- opt->command = CMD_RUN_TOR;
- options_init(opt);
- dflt = config_dup(&options_format, opt);
- clear_log_messages();
+ setup_options(opt, dflt);
r = config_get_lines(configuration, &cl, 1);
tt_int_op(r, OP_EQ, 0);
@@ -159,12 +166,110 @@ test_options_validate(void *arg)
"ServerTransportOptions did not parse",
LOG_WARN, "\"slingsnappy\" is not a k=v");
+ WANT_ERR("DirPort 8080\nDirCache 0",
+ "DirPort configured but DirCache disabled.");
+ WANT_ERR("BridgeRelay 1\nDirCache 0",
+ "We're a bridge but DirCache is disabled.");
+
clear_log_messages();
return;
}
+#define MEGABYTEIFY(mb) (U64_LITERAL(mb) << 20)
+static void
+test_have_enough_mem_for_dircache(void *arg)
+{
+ (void)arg;
+ or_options_t *opt=NULL;
+ or_options_t *dflt;
+ config_line_t *cl=NULL;
+ char *msg=NULL;;
+ int r;
+ const char *configuration = "ORPort 8080\nDirCache 1", *expect_errmsg;
+
+ setup_options(opt, dflt);
+ setup_log_callback();
+ (void)dflt;
+
+ r = config_get_lines(configuration, &cl, 1);
+ tt_int_op(r, OP_EQ, 0);
+
+ r = config_assign(&options_format, opt, cl, 0, 0, &msg);
+ tt_int_op(r, OP_EQ, 0);
+
+ /* 300 MB RAM available, DirCache enabled */
+ r = have_enough_mem_for_dircache(opt, MEGABYTEIFY(300), &msg);
+ tt_int_op(r, OP_EQ, 0);
+ tt_assert(!msg);
+
+ /* 200 MB RAM available, DirCache enabled */
+ r = have_enough_mem_for_dircache(opt, MEGABYTEIFY(200), &msg);
+ tt_int_op(r, OP_EQ, -1);
+ expect_errmsg = "Being a directory cache (default) with less than ";
+ if (!strstr(msg, expect_errmsg)) {
+ TT_DIE(("Expected error message <%s> from <%s>, but got <%s>.",
+ expect_errmsg, configuration, msg));
+ }
+ tor_free(msg);
+
+ configuration = "ORPort 8080\nDirCache 1\nBridgeRelay 1";
+ r = config_get_lines(configuration, &cl, 1);
+ tt_int_op(r, OP_EQ, 0);
+
+ r = config_assign(&options_format, opt, cl, 0, 0, &msg);
+ tt_int_op(r, OP_EQ, 0);
+
+ /* 300 MB RAM available, DirCache enabled, Bridge */
+ r = have_enough_mem_for_dircache(opt, MEGABYTEIFY(300), &msg);
+ tt_int_op(r, OP_EQ, 0);
+ tt_assert(!msg);
+
+ /* 200 MB RAM available, DirCache enabled, Bridge */
+ r = have_enough_mem_for_dircache(opt, MEGABYTEIFY(200), &msg);
+ tt_int_op(r, OP_EQ, -1);
+ expect_errmsg = "Running a Bridge with less than ";
+ if (!strstr(msg, expect_errmsg)) {
+ TT_DIE(("Expected error message <%s> from <%s>, but got <%s>.",
+ expect_errmsg, configuration, msg));
+ }
+ tor_free(msg);
+
+ configuration = "ORPort 8080\nDirCache 0";
+ r = config_get_lines(configuration, &cl, 1);
+ tt_int_op(r, OP_EQ, 0);
+
+ r = config_assign(&options_format, opt, cl, 0, 0, &msg);
+ tt_int_op(r, OP_EQ, 0);
+
+ /* 200 MB RAM available, DirCache disabled */
+ r = have_enough_mem_for_dircache(opt, MEGABYTEIFY(200), &msg);
+ tt_int_op(r, OP_EQ, 0);
+ tt_assert(!msg);
+
+ /* 300 MB RAM available, DirCache disabled */
+ r = have_enough_mem_for_dircache(opt, MEGABYTEIFY(300), &msg);
+ tt_int_op(r, OP_EQ, -1);
+ expect_errmsg = "DirCache is disabled and we are configured as a ";
+ if (!strstr(msg, expect_errmsg)) {
+ TT_DIE(("Expected error message <%s> from <%s>, but got <%s>.",
+ expect_errmsg, configuration, msg));
+ }
+ tor_free(msg);
+
+ clear_log_messages();
+
+ done:
+ if (msg)
+ tor_free(msg);
+ tor_free(dflt);
+ tor_free(opt);
+ tor_free(cl);
+ return;
+}
+
struct testcase_t options_tests[] = {
{ "validate", test_options_validate, TT_FORK, NULL, NULL },
+ { "mem_dircache", test_have_enough_mem_for_dircache, TT_FORK, NULL, NULL },
END_OF_TESTCASES
};