aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog32
-rw-r--r--changes/bug1139611
-rw-r--r--changes/ticket115286
-rw-r--r--configure.ac2
-rw-r--r--doc/tor.1.txt3
-rw-r--r--src/common/compat.c119
-rw-r--r--src/common/compat.h2
-rw-r--r--src/common/sandbox.c18
-rw-r--r--src/or/config.c80
-rwxr-xr-xsrc/or/control.c39
-rw-r--r--src/or/dnsserv.c29
-rw-r--r--src/or/entrynodes.c36
-rw-r--r--src/or/main.c1
-rw-r--r--src/or/networkstatus.c8
-rw-r--r--src/or/or.h5
-rw-r--r--src/or/transports.c63
-rw-r--r--src/or/transports.h2
-rw-r--r--src/test/test_util.c29
18 files changed, 409 insertions, 76 deletions
diff --git a/ChangeLog b/ChangeLog
index 790d1d487..aa932df5c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -43,6 +43,11 @@ Changes in version 0.2.5.4-alpha - 2014-04-??
break ties by preferring AES256 to AES128.) This resolves bugs
#11513, #11492, #11498, #11499. Bugs reported by 'cypherpunks'.
Bugfix on 0.2.4.8-alpha.
+ - Servers now trust themselves to have a better view than clients of
+ which TLS ciphersuites to choose. (Thanks to #11513, the server
+ list is now well-considered, whereas the client list has been
+ chosen mainly for anti-fingerprinting purposes.) Resolves ticket
+ 11528.
o Major bugfixes (undefined behavior):
- Fix two instances of possible undefined behavior in channeltls.c
@@ -70,6 +75,14 @@ Changes in version 0.2.5.4-alpha - 2014-04-??
connection. This prevents controllers from declaring that a
connection has failed because of "DONE" or other junk reasons.
Fixes bug 10431; bugfix on 0.2.1.1-alpha.
+ - Improve the warning message when trying to enable the Linux
+ sandbox code on a Tor built without libseccomp. Instead of
+ saying "Sandbox is not implemented on this platform", we now
+ explain that we to need be built with libseccomp. Fixes bug
+ 11543; bugfix on 0.2.5.1-alpha.
+ - Avoid generating spurious warnings and failure messages when
+ starting with DisableNetwork enabled. Fixes bug 11200 and bug
+ 10405; bugfix on 0.2.3.9-alpha.
o Minor bugfixes (closing channels):
- If write_to_buf() in connection_write_to_buf_impl_() ever fails,
@@ -127,6 +140,20 @@ Changes in version 0.2.5.4-alpha - 2014-04-??
- Stop accepting bridge lines containing hostnames. Doing so allowed
clients to perform DNS requests on the hostnames, which was not
sensible behavior. Fixes bug 10801; bugfix on 0.2.0.1-alpha.
+ - Fix a bug where a client-side Tor with pluggable transports
+ would take 60 seconds to bootstrap if a config re-read was
+ triggered at just the right timing during bootstrap. Refixes bug
+ 11156; bugfix on 0.2.5.3-alpha.
+ - Avoid 60-second delays in the bootstrapping process when Tor
+ is launching for a second time while using bridges. Fixes bug 9229;
+ bugfix on 0.2.0.3-alpha.
+
+ o Minor bugfixes (DNS):
+ - When receing a DNS query for an unsupported type, reply with
+ no answer rather than with a NOTIMPL error. This behavior isn't
+ correct either, but it will break fewer client programs, we hope.
+ Fixes bug 10268; bugfix on 0.2.0.1-alpha. Original patch
+ from "epoch".
o Minor bugfixes (exit):
- Stop leaking memory when we successfully resolve a PTR record.
@@ -152,6 +179,11 @@ Changes in version 0.2.5.4-alpha - 2014-04-??
- Demote the message that we give when a flushing connection times
out for too long from NOTICE to INFO. It was usually meaningless.
Resolves ticket 5286.
+ - Don't log so many notice-level bootstrapping messages at startup about
+ downloading descriptors. Previously, we'd log a notice whenever we
+ learned about more routers. Now, we only log a notice at every 5% of
+ progress. Fixes bug 9963.
+
o Minor features (performance, compatibility):
- Update the list of TLS cipehrsuites that a client advertises
diff --git a/changes/bug11396 b/changes/bug11396
new file mode 100644
index 000000000..fd263291d
--- /dev/null
+++ b/changes/bug11396
@@ -0,0 +1,11 @@
+ o Minor features (security):
+
+ - If you don't specify MaxMemInQueues yourself, Tor now tries to
+ pick a good value based on your total system memory. Previously,
+ the default was always 8 GB. You can still override the default by
+ setting MaxMemInQueues yourself. Resolves ticket 11396.
+
+ o Minor features (controller):
+ - Because of the fix for ticket 11396, the real limit for memory
+ usage may no longer match the configured MaxMemInQueues value.
+ The real limit is now exposed via GETINFO limits/max-mem-in-queues.
diff --git a/changes/ticket11528 b/changes/ticket11528
deleted file mode 100644
index 15daad995..000000000
--- a/changes/ticket11528
+++ /dev/null
@@ -1,6 +0,0 @@
- o Minor features:
- - Servers now trust themselves to have a better view than clients of
- which TLS ciphersuites to choose. (Thanks to #11513, the server
- list is now well-considered, whereas the client list has been
- chosen mainly for anti-fingerprinting purposes.) Resolves ticket
- 11528.
diff --git a/configure.ac b/configure.ac
index 07b23dbcf..4831b4e3e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -353,6 +353,7 @@ AC_CHECK_FUNCS(
strtok_r \
strtoull \
sysconf \
+ sysctl \
uname \
vasprintf \
_vscprintf
@@ -885,6 +886,7 @@ AC_CHECK_HEADERS(
sys/prctl.h \
sys/resource.h \
sys/socket.h \
+ sys/sysctl.h \
sys/syslimits.h \
sys/time.h \
sys/types.h \
diff --git a/doc/tor.1.txt b/doc/tor.1.txt
index d1556a554..94c7d40a6 100644
--- a/doc/tor.1.txt
+++ b/doc/tor.1.txt
@@ -1761,7 +1761,8 @@ is non-zero):
it has recovered at least 10% of this memory. Do not set this option too
low, or your relay may be unreliable under load. This option only
affects some queues, so the actual process size will be larger than
- this. (Default: 8GB)
+ this. If this option is set to 0, Tor will try to pick a reasonable
+ default based on your system's physical memory. (Default: 0)
DIRECTORY SERVER OPTIONS
------------------------
diff --git a/src/common/compat.c b/src/common/compat.c
index c5945fbd2..9b96a35fe 100644
--- a/src/common/compat.c
+++ b/src/common/compat.c
@@ -38,6 +38,9 @@
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
+#ifdef HAVE_SYS_SYSCTL_H
+#include <sys/sysctl.h>
+#endif
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
@@ -3329,3 +3332,119 @@ format_win32_error(DWORD err)
}
#endif
+#if defined(HW_PHYSMEM64)
+/* This appears to be an OpenBSD thing */
+#define INT64_HW_MEM HW_PHYSMEM64
+#elif defined(HW_MEMSIZE)
+/* OSX defines this one */
+#define INT64_HW_MEM HW_MEMSIZE
+#endif
+
+/**
+ * Helper: try to detect the total system memory, and return it. On failure,
+ * return 0.
+ */
+static uint64_t
+get_total_system_memory_impl(void)
+{
+#if defined(__linux__)
+ /* On linux, sysctl is deprecated. Because proc is so awesome that you
+ * shouldn't _want_ to write portable code, I guess? */
+ unsigned long long result=0;
+ int fd = -1;
+ char *s = NULL;
+ const char *cp;
+ size_t file_size=0;
+ if (-1 == (fd = tor_open_cloexec("/proc/meminfo",O_RDONLY,0)))
+ return 0;
+ s = read_file_to_str_until_eof(fd, 65536, &file_size);
+ if (!s)
+ goto err;
+ cp = strstr(s, "MemTotal:");
+ if (!cp)
+ goto err;
+ /* Use the system sscanf so that space will match a wider number of space */
+ if (sscanf(cp, "MemTotal: %llu kB\n", &result) != 1)
+ goto err;
+
+ close(fd);
+ tor_free(s);
+ return result * 1024;
+
+ err:
+ tor_free(s);
+ close(fd);
+ return 0;
+#elif defined (_WIN32)
+ /* Windows has MEMORYSTATUSEX; pretty straightforward. */
+ MEMORYSTATUSEX ms;
+ memset(&ms, 0, sizeof(ms));
+ ms.dwLength = sizeof(ms);
+ if (! GlobalMemoryStatusEx(&ms))
+ return 0;
+
+ return ms.ullTotalPhys;
+
+#elif defined(HAVE_SYSCTL) && defined(INT64_HW_MEM)
+ /* On many systems, HW_PYHSMEM is clipped to 32 bits; let's use a better
+ * variant if we know about it. */
+ uint64_t memsize = 0;
+ size_t len = sizeof(memsize);
+ int mib[2] = {CTL_HW, INT64_HW_MEM};
+ if (sysctl(mib,2,&memsize,&len,NULL,0))
+ return 0;
+
+ return memsize;
+
+#elif defined(HAVE_SYSCTL) && defined(HW_PHYSMEM)
+ /* On some systems (like FreeBSD I hope) you can use a size_t with
+ * HW_PHYSMEM. */
+ size_t memsize=0;
+ size_t len = sizeof(memsize);
+ int mib[2] = {CTL_HW, HW_USERMEM};
+ if (sysctl(mib,2,&memsize,&len,NULL,0))
+ return -1;
+
+ return memsize;
+
+#else
+ /* I have no clue. */
+ return 0;
+#endif
+}
+
+/**
+ * Try to find out how much physical memory the system has. On success,
+ * return 0 and set *<b>mem_out</b> to that value. On failure, return -1.
+ */
+int
+get_total_system_memory(size_t *mem_out)
+{
+ static size_t mem_cached=0;
+ uint64_t m = get_total_system_memory_impl();
+ if (0 == m) {
+ /* We couldn't find our memory total */
+ if (0 == mem_cached) {
+ /* We have no cached value either */
+ *mem_out = 0;
+ return -1;
+ }
+
+ *mem_out = mem_cached;
+ return 0;
+ }
+
+#if SIZE_T_MAX != UINT64_MAX
+ if (m > SIZE_T_MAX) {
+ /* I think this could happen if we're a 32-bit Tor running on a 64-bit
+ * system: we could have more system memory than would fit in a
+ * size_t. */
+ m = SIZE_T_MAX;
+ }
+#endif
+
+ *mem_out = mem_cached = (size_t) m;
+
+ return -1;
+}
+
diff --git a/src/common/compat.h b/src/common/compat.h
index 9a381fb97..314b1aa00 100644
--- a/src/common/compat.h
+++ b/src/common/compat.h
@@ -638,6 +638,8 @@ char *make_path_absolute(char *fname);
char **get_environment(void);
+int get_total_system_memory(size_t *mem_out);
+
int spawn_func(void (*func)(void *), void *data);
void spawn_exit(void) ATTR_NORETURN;
diff --git a/src/common/sandbox.c b/src/common/sandbox.c
index 4224e03e2..4ce9aa920 100644
--- a/src/common/sandbox.c
+++ b/src/common/sandbox.c
@@ -1613,21 +1613,19 @@ sandbox_init(sandbox_cfg_t *cfg)
#if defined(USE_LIBSECCOMP)
return initialise_libseccomp_sandbox(cfg);
-#elif defined(_WIN32)
+#elif defined(__linux__)
(void)cfg;
- log_warn(LD_BUG,"Windows sandboxing is not implemented. The feature is "
- "currently disabled.");
+ log_warn(LD_GENERAL,
+ "This version of Tor was built without support for sanboxing. To "
+ "build with support for sandboxing on Linux, you must have "
+ "libseccomp and its necessary header files (e.g. seccomp.h).");
return 0;
-#elif defined(TARGET_OS_MAC)
- (void)cfg;
- log_warn(LD_BUG,"Mac OSX sandboxing is not implemented. The feature is "
- "currently disabled");
- return 0;
#else
(void)cfg;
- log_warn(LD_BUG,"Sandboxing is not implemented for your platform. The "
- "feature is currently disabled");
+ log_warn(LD_GENERAL,
+ "Currently, sandboxing is only implemented on Linux. The feature "
+ "is disabled on your platform.");
return 0;
#endif
}
diff --git a/src/or/config.c b/src/or/config.c
index a5407dd4e..3954c582e 100644
--- a/src/or/config.c
+++ b/src/or/config.c
@@ -307,7 +307,7 @@ static config_var_t option_vars_[] = {
V(MaxAdvertisedBandwidth, MEMUNIT, "1 GB"),
V(MaxCircuitDirtiness, INTERVAL, "10 minutes"),
V(MaxClientCircuitsPending, UINT, "32"),
- V(MaxMemInQueues, MEMUNIT, "8 GB"),
+ VAR("MaxMeminQueues", MEMUNIT, MaxMemInQueues_raw, "0"),
OBSOLETE("MaxOnionsPending"),
V(MaxOnionQueueDelay, MSEC_INTERVAL, "1750 msec"),
V(MinMeasuredBWsForAuthToIgnoreAdvertised, INT, "500"),
@@ -565,6 +565,8 @@ static void config_maybe_load_geoip_files_(const or_options_t *options,
static int options_validate_cb(void *old_options, void *options,
void *default_options,
int from_setconf, char **msg);
+static uint64_t compute_real_max_mem_in_queues(const uint64_t val,
+ int log_guess);
/** Magic value for or_options_t. */
#define OR_OPTIONS_MAGIC 9090909
@@ -1445,6 +1447,12 @@ options_act(const or_options_t *old_options)
sweep_transport_list();
sweep_proxy_list();
+ /* Start the PT proxy configuration. By doing this configuration
+ here, we also figure out which proxies need to be restarted and
+ which not. */
+ if (pt_proxies_configuration_pending() && !net_is_disabled())
+ pt_configure_remaining_proxies();
+
/* Bail out at this point if we're not going to be a client or server:
* we want to not fork, and to log stuff to stderr. */
if (!running_tor)
@@ -2818,11 +2826,9 @@ options_validate(or_options_t *old_options, or_options_t *options,
REJECT("If EntryNodes is set, UseEntryGuards must be enabled.");
}
- if (options->MaxMemInQueues < (256 << 20)) {
- log_warn(LD_CONFIG, "MaxMemInQueues must be at least 256 MB for now. "
- "Ideally, have it as large as you can afford.");
- options->MaxMemInQueues = (256 << 20);
- }
+ options->MaxMemInQueues =
+ compute_real_max_mem_in_queues(options->MaxMemInQueues_raw,
+ server_mode(options));
options->AllowInvalid_ = 0;
@@ -3572,6 +3578,68 @@ options_validate(or_options_t *old_options, or_options_t *options,
#undef COMPLAIN
}
+/* Given the value that the user has set for MaxMemInQueues, compute the
+ * actual maximum value. We clip this value if it's too low, and autodetect
+ * it if it's set to 0. */
+static uint64_t
+compute_real_max_mem_in_queues(const uint64_t val, int log_guess)
+{
+ uint64_t result;
+
+ if (val == 0) {
+#define ONE_GIGABYTE (U64_LITERAL(1) << 30)
+#define ONE_MEGABYTE (U64_LITERAL(1) << 20)
+#if SIZEOF_VOID_P >= 8
+#define MAX_DEFAULT_MAXMEM (8*ONE_GIGABYTE)
+#else
+#define MAX_DEFAULT_MAXMEM (2*ONE_GIGABYTE)
+#endif
+ /* The user didn't pick a memory limit. Choose a very large one
+ * that is still smaller than the system memory */
+ static int notice_sent = 0;
+ size_t ram = 0;
+ if (get_total_system_memory(&ram) < 0) {
+ /* We couldn't determine our total system memory! */
+#if SIZEOF_VOID_P >= 8
+ /* 64-bit system. Let's hope for 8 GB. */
+ result = 8 * ONE_GIGABYTE;
+#else
+ /* (presumably) 32-bit system. Let's hope for 1 GB. */
+ result = ONE_GIGABYTE;
+#endif
+ } else {
+ /* We detected it, so let's pick 3/4 of the total RAM as our limit. */
+ const uint64_t avail = (ram / 4) * 3;
+
+ /* Make sure it's in range from 0.25 GB to 8 GB. */
+ if (avail > MAX_DEFAULT_MAXMEM) {
+ /* If you want to use more than this much RAM, you need to configure
+ it yourself */
+ result = MAX_DEFAULT_MAXMEM;
+ } else if (avail < ONE_GIGABYTE / 4) {
+ result = ONE_GIGABYTE / 4;
+ } else {
+ result = avail;
+ }
+ }
+ if (log_guess && ! notice_sent) {
+ log_notice(LD_CONFIG, "%sMaxMemInQueues is set to "U64_FORMAT" MB. "
+ "You can override this by setting MaxMemInQueues by hand.",
+ ram ? "Based on detected system memory, " : "",
+ U64_PRINTF_ARG(result / ONE_MEGABYTE));
+ notice_sent = 1;
+ }
+ return result;
+ } else if (val < ONE_GIGABYTE / 4) {
+ log_warn(LD_CONFIG, "MaxMemInQueues must be at least 256 MB for now. "
+ "Ideally, have it as large as you can afford.");
+ return ONE_GIGABYTE / 4;
+ } else {
+ /* The value was fine all along */
+ return val;
+ }
+}
+
/** Helper: return true iff s1 and s2 are both NULL, or both non-NULL
* equal strings. */
static int
diff --git a/src/or/control.c b/src/or/control.c
index c91705257..d571900ac 100755
--- a/src/or/control.c
+++ b/src/or/control.c
@@ -1504,6 +1504,9 @@ getinfo_helper_misc(control_connection_t *conn, const char *question,
int max_fds=-1;
set_max_file_descriptors(0, &max_fds);
tor_asprintf(answer, "%d", max_fds);
+ } else if (!strcmp(question, "limits/max-mem-in-queues")) {
+ tor_asprintf(answer, U64_FORMAT,
+ U64_PRINTF_ARG(get_options()->MaxMemInQueues));
} else if (!strcmp(question, "dir-usage")) {
*answer = directory_dump_request_log();
} else if (!strcmp(question, "fingerprint")) {
@@ -2184,6 +2187,7 @@ static const getinfo_item_t getinfo_items[] = {
ITEM("process/user", misc,
"Username under which the tor process is running."),
ITEM("process/descriptor-limit", misc, "File descriptor limit."),
+ ITEM("limits/max-mem-in-queues", misc, "Actual limit on memory in queues"),
ITEM("dir-usage", misc, "Breakdown of bytes transferred over DirPort."),
PREFIX("desc-annotations/id/", dir, "Router annotations by hexdigest."),
PREFIX("dir/server/", dir,"Router descriptors as retrieved from a DirPort."),
@@ -4822,16 +4826,28 @@ bootstrap_status_to_string(bootstrap_status_t s, const char **tag,
* Tor initializes. */
static int bootstrap_percent = BOOTSTRAP_STATUS_UNDEF;
+/** As bootstrap_percent, but holds the bootstrapping level at which we last
+ * logged a NOTICE-level message. We use this, plus BOOTSTRAP_PCT_INCREMENT,
+ * to avoid flooding the log with a new message every time we get a few more
+ * microdescriptors */
+static int notice_bootstrap_percent = 0;
+
/** How many problems have we had getting to the next bootstrapping phase?
* These include failure to establish a connection to a Tor relay,
* failures to finish the TLS handshake, failures to validate the
* consensus document, etc. */
static int bootstrap_problems = 0;
-/* We only tell the controller once we've hit a threshold of problems
+/** We only tell the controller once we've hit a threshold of problems
* for the current phase. */
#define BOOTSTRAP_PROBLEM_THRESHOLD 10
+/** When our bootstrapping progress level changes, but our bootstrapping
+ * status has not advanced, we only log at NOTICE when we have made at least
+ * this much progress.
+ */
+#define BOOTSTRAP_PCT_INCREMENT 5
+
/** Called when Tor has made progress at bootstrapping its directory
* information and initial circuits.
*
@@ -4851,7 +4867,7 @@ control_event_bootstrap(bootstrap_status_t status, int progress)
* can't distinguish what the connection is going to be for. */
if (status == BOOTSTRAP_STATUS_HANDSHAKE) {
if (bootstrap_percent < BOOTSTRAP_STATUS_CONN_OR) {
- status = BOOTSTRAP_STATUS_HANDSHAKE_DIR;
+ status = BOOTSTRAP_STATUS_HANDSHAKE_DIR;
} else {
status = BOOTSTRAP_STATUS_HANDSHAKE_OR;
}
@@ -4859,9 +4875,19 @@ control_event_bootstrap(bootstrap_status_t status, int progress)
if (status > bootstrap_percent ||
(progress && progress > bootstrap_percent)) {
+ int loglevel = LOG_NOTICE;
bootstrap_status_to_string(status, &tag, &summary);
- tor_log(status ? LOG_NOTICE : LOG_INFO, LD_CONTROL,
- "Bootstrapped %d%%: %s.", progress ? progress : status, summary);
+
+ if (status <= bootstrap_percent &&
+ (progress < notice_bootstrap_percent + BOOTSTRAP_PCT_INCREMENT)) {
+ /* We log the message at info if the status hasn't advanced, and if less
+ * than BOOTSTRAP_PCT_INCREMENT progress has been made.
+ */
+ loglevel = LOG_INFO;
+ }
+
+ tor_log(loglevel, LD_CONTROL,
+ "Bootstrapped %d%%: %s", progress ? progress : status, summary);
tor_snprintf(buf, sizeof(buf),
"BOOTSTRAP PROGRESS=%d TAG=%s SUMMARY=\"%s\"",
progress ? progress : status, tag, summary);
@@ -4877,6 +4903,11 @@ control_event_bootstrap(bootstrap_status_t status, int progress)
bootstrap_percent = progress;
bootstrap_problems = 0; /* Progress! Reset our problem counter. */
}
+ if (loglevel == LOG_NOTICE &&
+ bootstrap_percent > notice_bootstrap_percent) {
+ /* Remember that we gave a notice at this level. */
+ notice_bootstrap_percent = bootstrap_percent;
+ }
}
}
diff --git a/src/or/dnsserv.c b/src/or/dnsserv.c
index 4190e9cc2..ecd45be77 100644
--- a/src/or/dnsserv.c
+++ b/src/or/dnsserv.c
@@ -35,7 +35,7 @@ evdns_server_callback(struct evdns_server_request *req, void *data_)
entry_connection_t *entry_conn;
edge_connection_t *conn;
int i = 0;
- struct evdns_server_question *q = NULL;
+ struct evdns_server_question *q = NULL, *supported_q = NULL;
struct sockaddr_storage addr;
struct sockaddr *sa;
int addrlen;
@@ -87,31 +87,37 @@ evdns_server_callback(struct evdns_server_request *req, void *data_)
for (i = 0; i < req->nquestions; ++i) {
if (req->questions[i]->dns_question_class != EVDNS_CLASS_INET)
continue;
+ if (! q)
+ q = req->questions[i];
switch (req->questions[i]->type) {
case EVDNS_TYPE_A:
case EVDNS_TYPE_AAAA:
case EVDNS_TYPE_PTR:
- q = req->questions[i];
+ /* We always pick the first one of these questions, if there is
+ one. */
+ if (! supported_q)
+ supported_q = q;
+ break;
default:
break;
}
}
+ if (supported_q)
+ q = supported_q;
if (!q) {
log_info(LD_APP, "None of the questions we got were ones we're willing "
"to support. Sending NOTIMPL.");
evdns_server_request_respond(req, DNS_ERR_NOTIMPL);
return;
}
- if (q->type != EVDNS_TYPE_A && q->type != EVDNS_TYPE_AAAA) {
- tor_assert(q->type == EVDNS_TYPE_PTR);
- }
/* Make sure the name isn't too long: This should be impossible, I think. */
if (err == DNS_ERR_NONE && strlen(q->name) > MAX_SOCKS_ADDR_LEN-1)
err = DNS_ERR_FORMAT;
- if (err != DNS_ERR_NONE) {
- /* We got an error? Then send back an answer immediately; we're done. */
+ if (err != DNS_ERR_NONE || !supported_q) {
+ /* We got an error? There's no question we're willing to answer? Then
+ * send back an answer immediately; we're done. */
evdns_server_request_respond(req, err);
return;
}
@@ -126,12 +132,15 @@ evdns_server_callback(struct evdns_server_request *req, void *data_)
TO_CONN(conn)->port = port;
TO_CONN(conn)->address = tor_dup_addr(&tor_addr);
- if (q->type == EVDNS_TYPE_A || q->type == EVDNS_TYPE_AAAA)
+ if (q->type == EVDNS_TYPE_A || q->type == EVDNS_TYPE_AAAA ||
+ q->type == EVDNS_QTYPE_ALL) {
entry_conn->socks_request->command = SOCKS_COMMAND_RESOLVE;
- else
+ } else {
+ tor_assert(q->type == EVDNS_TYPE_PTR);
entry_conn->socks_request->command = SOCKS_COMMAND_RESOLVE_PTR;
+ }
- if (q->type == EVDNS_TYPE_A) {
+ if (q->type == EVDNS_TYPE_A || q->type == EVDNS_QTYPE_ALL) {
entry_conn->ipv4_traffic_ok = 1;
entry_conn->ipv6_traffic_ok = 0;
entry_conn->prefer_ipv6_traffic = 0;
diff --git a/src/or/entrynodes.c b/src/or/entrynodes.c
index b374ac7a3..70587bd75 100644
--- a/src/or/entrynodes.c
+++ b/src/or/entrynodes.c
@@ -70,7 +70,9 @@ static int entry_guards_dirty = 0;
static void bridge_free(bridge_info_t *bridge);
static const node_t *choose_random_entry_impl(cpath_build_state_t *state,
int for_directory,
- dirinfo_type_t dirtype);
+ dirinfo_type_t dirtype,
+ int *n_options_out);
+static int num_bridges_usable(void);
/** Return the list of entry guards, creating it if necessary. */
const smartlist_t *
@@ -982,7 +984,7 @@ node_can_handle_dirinfo(const node_t *node, dirinfo_type_t dirinfo)
const node_t *
choose_random_entry(cpath_build_state_t *state)
{
- return choose_random_entry_impl(state, 0, 0);
+ return choose_random_entry_impl(state, 0, 0, NULL);
}
/** Pick a live (up and listed) directory guard from entry_guards for
@@ -990,13 +992,13 @@ choose_random_entry(cpath_build_state_t *state)
const node_t *
choose_random_dirguard(dirinfo_type_t type)
{
- return choose_random_entry_impl(NULL, 1, type);
+ return choose_random_entry_impl(NULL, 1, type, NULL);
}
/** Helper for choose_random{entry,dirguard}. */
static const node_t *
choose_random_entry_impl(cpath_build_state_t *state, int for_directory,
- dirinfo_type_t dirinfo_type)
+ dirinfo_type_t dirinfo_type, int *n_options_out)
{
const or_options_t *options = get_options();
smartlist_t *live_entry_guards = smartlist_new();
@@ -1010,6 +1012,9 @@ choose_random_entry_impl(cpath_build_state_t *state, int for_directory,
int need_descriptor = !for_directory;
const int num_needed = decide_num_guards(options, for_directory);
+ if (n_options_out)
+ *n_options_out = 0;
+
if (chosen_exit) {
nodelist_add_node_and_family(exit_family, chosen_exit);
consider_exit_family = 1;
@@ -1136,6 +1141,8 @@ choose_random_entry_impl(cpath_build_state_t *state, int for_directory,
* *double*-weight our guard selection. */
node = smartlist_choose(live_entry_guards);
}
+ if (n_options_out)
+ *n_options_out = smartlist_len(live_entry_guards);
smartlist_free(live_entry_guards);
smartlist_free(exit_family);
return node;
@@ -2166,7 +2173,7 @@ learned_bridge_descriptor(routerinfo_t *ri, int from_cache)
tor_assert(ri);
tor_assert(ri->purpose == ROUTER_PURPOSE_BRIDGE);
if (get_options()->UseBridges) {
- int first = !any_bridge_descriptors_known();
+ int first = num_bridges_usable() <= 1;
bridge_info_t *bridge = get_configured_bridge_by_routerinfo(ri);
time_t now = time(NULL);
router_set_status(ri->cache_info.identity_digest, 1);
@@ -2188,14 +2195,15 @@ learned_bridge_descriptor(routerinfo_t *ri, int from_cache)
* our entry node list */
entry_guard_register_connect_status(ri->cache_info.identity_digest,
1, 0, now);
- if (first)
+ if (first) {
routerlist_retry_directory_downloads(now);
+ }
}
}
}
-/** Return 1 if any of our entry guards have descriptors that
- * are marked with purpose 'bridge' and are running. Else return 0.
+/** Return the number of bridges that have descriptors that
+ * are marked with purpose 'bridge' and are running.
*
* We use this function to decide if we're ready to start building
* circuits through our bridges, or if we need to wait until the
@@ -2207,6 +2215,18 @@ any_bridge_descriptors_known(void)
return choose_random_entry(NULL) != NULL;
}
+/** Return the number of bridges that have descriptors that are marked with
+ * purpose 'bridge' and are running.
+ */
+static int
+num_bridges_usable(void)
+{
+ int n_options = 0;
+ tor_assert(get_options()->UseBridges);
+ (void) choose_random_entry_impl(NULL, 0, 0, &n_options);
+ return n_options;
+}
+
/** Return 1 if we have at least one descriptor for an entry guard
* (bridge or member of EntryNodes) and all descriptors we know are
* down. Else return 0. If <b>act</b> is 1, then mark the down guards
diff --git a/src/or/main.c b/src/or/main.c
index 4770b7e6d..6713d8036 100644
--- a/src/or/main.c
+++ b/src/or/main.c
@@ -2767,6 +2767,7 @@ sandbox_init_filter(void)
tor_strdup("/dev/urandom"),
tor_strdup("/dev/random"),
tor_strdup("/etc/hosts"),
+ tor_strdup("/proc/meminfo"),
NULL, 0
);
if (options->ServerDNSResolvConfFile)
diff --git a/src/or/networkstatus.c b/src/or/networkstatus.c
index b8ac2e05f..ef450073e 100644
--- a/src/or/networkstatus.c
+++ b/src/or/networkstatus.c
@@ -909,6 +909,14 @@ should_delay_dir_fetches(const or_options_t *options, const char **msg_out)
*msg_out = NULL;
}
+ if (options->DisableNetwork) {
+ if (msg_out) {
+ *msg_out = "DisableNetwork is set.";
+ }
+ log_info(LD_DIR, "Delaying dir fetches (DisableNetwork is set)");
+ return 1;
+ }
+
if (options->UseBridges) {
if (!any_bridge_descriptors_known()) {
if (msg_out) {
diff --git a/src/or/or.h b/src/or/or.h
index 4ca7ecc60..701877c64 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -3491,7 +3491,10 @@ typedef struct {
config_line_t *DirPort_lines;
config_line_t *DNSPort_lines; /**< Ports to listen on for DNS requests. */
- uint64_t MaxMemInQueues; /**< If we have more memory than this allocated
+ /* MaxMemInQueues value as input by the user. We clean this up to be
+ * MaxMemInQueues. */
+ uint64_t MaxMemInQueues_raw;
+ uint64_t MaxMemInQueues;/**< If we have more memory than this allocated
* for queues and buffers, run the OOM handler */
/** @name port booleans
diff --git a/src/or/transports.c b/src/or/transports.c
index 7e496fe21..dc3075416 100644
--- a/src/or/transports.c
+++ b/src/or/transports.c
@@ -51,35 +51,37 @@
* logic, because of race conditions that can cause dangling
* pointers. ]
*
- * <b>In even more detail, this is what happens when a SIGHUP
- * occurs:</b>
+ * <b>In even more detail, this is what happens when a config read
+ * (like a SIGHUP or a SETCONF) occurs:</b>
*
* We immediately destroy all unconfigured proxies (We shouldn't have
- * unconfigured proxies in the first place, except when SIGHUP rings
- * immediately after tor is launched.).
+ * unconfigured proxies in the first place, except when the config
+ * read happens immediately after tor is launched.).
*
* We mark all managed proxies and transports to signify that they
* must be removed if they don't contribute by the new torrc
* (we mark using the <b>marked_for_removal</b> element).
* We also mark all managed proxies to signify that they might need to
* be restarted so that they end up supporting all the transports the
- * new torrc wants them to support (using the <b>got_hup</b> element).
+ * new torrc wants them to support
+ * (we mark using the <b>was_around_before_config_read</b> element).
* We also clear their <b>transports_to_launch</b> list so that we can
* put there the transports we need to launch according to the new
* torrc.
*
* We then start parsing torrc again.
*
- * Everytime we encounter a transport line using a known pre-SIGHUP
- * managed proxy, we cleanse that proxy from the removal mark.
- * We also mark it as unconfigured so that on the next scheduled
- * events tick, we investigate whether we need to restart the proxy
- * so that it also spawns the new transports.
- * If the post-SIGHUP <b>transports_to_launch</b> list is identical to
- * the pre-SIGHUP one, it means that no changes were introduced to
- * this proxy during the SIGHUP and no restart has to take place.
+ * Everytime we encounter a transport line using a managed proxy that
+ * was around before the config read, we cleanse that proxy from the
+ * removal mark. We also toggle the <b>check_if_restarts_needed</b>
+ * flag, so that on the next <b>pt_configure_remaining_proxies</b>
+ * tick, we investigate whether we need to restart the proxy so that
+ * it also spawns the new transports. If the post-config-read
+ * <b>transports_to_launch</b> list is identical to the pre-config-read
+ * one, it means that no changes were introduced to this proxy during
+ * the config read and no restart has to take place.
*
- * During the post-SIGHUP torrc parsing, we unmark all transports
+ * During the post-config-read torrc parsing, we unmark all transports
* spawned by managed proxies that we find in our torrc.
* We do that so that if we don't need to restart a managed proxy, we
* can continue using its old transports normally.
@@ -534,8 +536,7 @@ launch_managed_proxy(managed_proxy_t *mp)
}
/** Check if any of the managed proxies we are currently trying to
- * configure have anything new to say. This is called from
- * run_scheduled_events(). */
+ * configure has anything new to say. */
void
pt_configure_remaining_proxies(void)
{
@@ -555,11 +556,12 @@ pt_configure_remaining_proxies(void)
tor_assert(mp->conf_state != PT_PROTO_BROKEN &&
mp->conf_state != PT_PROTO_FAILED_LAUNCH);
- if (mp->got_hup) {
- mp->got_hup = 0;
+ if (mp->was_around_before_config_read) {
+ /* This proxy is marked by a config read. Check whether we need
+ to restart it. */
+
+ mp->was_around_before_config_read = 0;
- /* This proxy is marked by a SIGHUP. Check whether we need to
- restart it. */
if (proxy_needs_restart(mp)) {
log_info(LD_GENERAL, "Preparing managed proxy '%s' for restart.",
mp->argv[0]);
@@ -1364,19 +1366,20 @@ pt_kickstart_proxy(const smartlist_t *transport_list,
managed_proxy_create(transport_list, proxy_argv, is_server);
} else { /* known proxy. add its transport to its transport list */
- if (mp->got_hup) {
- /* If the managed proxy we found is marked by a SIGHUP, it means
- that it's not useless and should be kept. If it's marked for
- removal, unmark it and increase the unconfigured proxies so
- that we try to restart it if we need to. Afterwards, check if
- a transport_t for 'transport' used to exist before the SIGHUP
- and make sure it doesn't get deleted because we might reuse
- it. */
+ if (mp->was_around_before_config_read) {
+ /* If this managed proxy was around even before we read the
+ config this time, it means that it was already enabled before
+ and is not useless and should be kept. If it's marked for
+ removal, unmark it and make sure that we check whether it
+ needs to be restarted. */
if (mp->marked_for_removal) {
mp->marked_for_removal = 0;
check_if_restarts_needed = 1;
}
+ /* For each new transport, check if the managed proxy used to
+ support it before the SIGHUP. If that was the case, make sure
+ it doesn't get removed because we might reuse it. */
SMARTLIST_FOREACH_BEGIN(transport_list, const char *, transport) {
old_transport = transport_get_by_name(transport);
if (old_transport)
@@ -1425,8 +1428,10 @@ pt_prepare_proxy_list_for_config_read(void)
tor_assert(mp->conf_state == PT_PROTO_COMPLETED);
+ /* Mark all proxies for removal, and also note that they have been
+ here before the config read. */
mp->marked_for_removal = 1;
- mp->got_hup = 1;
+ mp->was_around_before_config_read = 1;
SMARTLIST_FOREACH(mp->transports_to_launch, char *, t, tor_free(t));
smartlist_clear(mp->transports_to_launch);
} SMARTLIST_FOREACH_END(mp);
diff --git a/src/or/transports.h b/src/or/transports.h
index 7b524f207..1365ead00 100644
--- a/src/or/transports.h
+++ b/src/or/transports.h
@@ -97,7 +97,7 @@ typedef struct {
* this flag to signify that this proxy might need to be restarted
* so that it can listen for other transports according to the new
* torrc. */
- unsigned int got_hup : 1;
+ unsigned int was_around_before_config_read : 1;
/* transports to-be-launched by this proxy */
smartlist_t *transports_to_launch;
diff --git a/src/test/test_util.c b/src/test/test_util.c
index 08efd453c..6d6b6dbdf 100644
--- a/src/test/test_util.c
+++ b/src/test/test_util.c
@@ -3612,6 +3612,34 @@ test_util_socketpair(void *arg)
tor_close_socket(fds[1]);
}
+static void
+test_util_max_mem(void *arg)
+{
+ size_t memory1, memory2;
+ int r, r2;
+ (void) arg;
+
+ r = get_total_system_memory(&memory1);
+ r2 = get_total_system_memory(&memory2);
+ tt_int_op(r, ==, r2);
+ tt_int_op(memory2, ==, memory1);
+
+ TT_BLATHER(("System memory: "U64_FORMAT, U64_PRINTF_ARG(memory1)));
+
+ if (r==0) {
+ /* You have at least a megabyte. */
+ tt_int_op(memory1, >, (1<<20));
+ } else {
+ /* You do not have a petabyte. */
+#if SIZEOF_SIZE_T == SIZEOF_UINT64_T
+ tt_int_op(memory1, <, (U64_LITERAL(1)<<50));
+#endif
+ }
+
+ done:
+ ;
+}
+
struct testcase_t util_tests[] = {
UTIL_LEGACY(time),
UTIL_TEST(parse_http_time, 0),
@@ -3675,6 +3703,7 @@ struct testcase_t util_tests[] = {
(void*)"0" },
{ "socketpair_ersatz", test_util_socketpair, TT_FORK,
&socketpair_setup, (void*)"1" },
+ UTIL_TEST(max_mem, 0),
END_OF_TESTCASES
};