summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2011-05-16 11:01:23 -0400
committerNick Mathewson <nickm@torproject.org>2011-05-16 11:01:23 -0400
commitfd105e1048001ec4498116e7db5304bf7a1c90ca (patch)
tree9271c04d6cc726ef130d44843df8ef73590ead73
parentda805cea47ee518ab1481e1547c7f8704dbf19f4 (diff)
parent83fe07d3f26aff703230305c9ff529592af32d4f (diff)
downloadtor-fd105e1048001ec4498116e7db5304bf7a1c90ca.tar.gz
tor-fd105e1048001ec4498116e7db5304bf7a1c90ca.zip
Merge remote-tracking branch 'origin/maint-0.2.2' into release-0.2.2
-rw-r--r--changes/bug134513
-rw-r--r--changes/bug2732-simple7
-rw-r--r--changes/bug2792_checkdir8
-rw-r--r--changes/bug29725
-rw-r--r--changes/bug30194
-rw-r--r--changes/bug30264
-rw-r--r--changes/bug31757
-rw-r--r--doc/tor.1.txt5
-rw-r--r--src/common/compat.c39
-rw-r--r--src/common/compat.h2
-rw-r--r--src/common/container.c21
-rw-r--r--src/common/container.h4
-rw-r--r--src/common/di_ops.c14
-rw-r--r--src/common/di_ops.h1
-rw-r--r--src/common/util.c58
-rw-r--r--src/common/util.h7
-rw-r--r--src/or/circuitbuild.c57
-rw-r--r--src/or/circuitbuild.h9
-rw-r--r--src/or/circuituse.c51
-rw-r--r--src/or/circuituse.h2
-rw-r--r--src/or/config.c40
-rw-r--r--src/or/connection.c49
-rw-r--r--src/or/connection_edge.c51
-rw-r--r--src/or/connection_edge.h1
-rw-r--r--src/or/directory.c5
-rw-r--r--src/or/dirvote.c13
-rw-r--r--src/or/main.c1
-rw-r--r--src/or/or.h4
-rw-r--r--src/or/routerlist.c27
-rw-r--r--src/test/test_util.c30
30 files changed, 450 insertions, 89 deletions
diff --git a/changes/bug1345 b/changes/bug1345
new file mode 100644
index 0000000000..0c9375a35d
--- /dev/null
+++ b/changes/bug1345
@@ -0,0 +1,13 @@
+ o Minor bugfixes:
+ - On SIGHUP, do not clear out all TrackHostExits mappings, client DNS
+ cache entries, and virtual address mappings: that's what NEWNYM is
+ for. Bugfix on Tor 0.1.0.1-rc; fixes bug 1345.
+ - When TrackHostExits is changed from a controller, remove any
+ mappings for hosts that should no longer have their exits tracked.
+ Bugfix on Tor 0.1.0.1-rc.
+ - When VirtualAddrNetwork option is changed from a controller,
+ remove any mappings for hosts that were automapped to
+ that network. Bugfix on 0.1.1.19-rc.
+ - When one of the AutomapHosts* options is changed from a
+ controller, remove any mappings for hosts that should no longer be
+ automapped. Bugfix on 0.2.0.1-alpha.
diff --git a/changes/bug2732-simple b/changes/bug2732-simple
new file mode 100644
index 0000000000..367836152d
--- /dev/null
+++ b/changes/bug2732-simple
@@ -0,0 +1,7 @@
+ o Minor bugfixes
+ - Do not reject hidden service descriptors simply because we don't
+ think we have not been assigned the HSDir flag. Clients and
+ hidden services can have a more up-to-date view of the network
+ consensus, and if they think that the directory authorities
+ list us a HSDir, we might actually be one. Related to bug 2732;
+ bugfix on 0.2.0.10-alpha.
diff --git a/changes/bug2792_checkdir b/changes/bug2792_checkdir
new file mode 100644
index 0000000000..10de1deb2d
--- /dev/null
+++ b/changes/bug2792_checkdir
@@ -0,0 +1,8 @@
+ o Minor features:
+ - Tor now refuses to create a ControlSocket in a directory that is
+ world-readable (or group-readable if ControlSocketsGroupWritable
+ is 0). This is necessary because some operating systems do not
+ check the permissions on an AF_UNIX socket when programs try to
+ connect to it. Checking permissions on the directory holding
+ the socket, however, seems to work everywhere.
+
diff --git a/changes/bug2972 b/changes/bug2972
new file mode 100644
index 0000000000..26afcca421
--- /dev/null
+++ b/changes/bug2972
@@ -0,0 +1,5 @@
+ o Minor features:
+ - Allow ControlSockets to be group-writable when the
+ ControlSocksGroupWritable configuration option is turned on. Patch
+ by Jérémy Bobbio; implements ticket 2972.
+
diff --git a/changes/bug3019 b/changes/bug3019
new file mode 100644
index 0000000000..4df709fb3b
--- /dev/null
+++ b/changes/bug3019
@@ -0,0 +1,4 @@
+ o Minor bugfixes:
+ - Do not reset the bridge descriptor download status every time we
+ re-parse our configuration or get a configuration change. Fixes
+ bug 3019; bugfix on Tor 0.2.0.3-alpha.
diff --git a/changes/bug3026 b/changes/bug3026
new file mode 100644
index 0000000000..c0c0a3860a
--- /dev/null
+++ b/changes/bug3026
@@ -0,0 +1,4 @@
+ o Minor bugfixes (directory authority)
+ - Do not upload our own vote or signature set to ourself. It would
+ tell us nothing new. Also, as of Tor 0.2.2.24-alpha, we started
+ to warn about receiving duplicate votes. Resolves bug 3026.
diff --git a/changes/bug3175 b/changes/bug3175
new file mode 100644
index 0000000000..3360fbce00
--- /dev/null
+++ b/changes/bug3175
@@ -0,0 +1,7 @@
+ o Minor bugfixes:
+ - Resolve an untriggerable issue in smartlist_string_num_isin(),
+ where if the function had ever in the future been used to check
+ for the presence of a too-large number, it would have given an
+ incorrect result. (Fortunately, we only used it for 16-bit
+ values.) Fixes bug 3175; bugfix on Tor 0.1.0.1-rc.
+
diff --git a/doc/tor.1.txt b/doc/tor.1.txt
index d95d764c67..1815a8d963 100644
--- a/doc/tor.1.txt
+++ b/doc/tor.1.txt
@@ -167,6 +167,11 @@ Other options can be specified either on the command-line (--option
Like ControlPort, but listens on a Unix domain socket, rather than a TCP
socket. (Unix and Unix-like systems only.)
+**ControlSocketsGroupWritable** **0**|**1**::
+ If this option is set to 0, don't allow the filesystem group to read and
+ write unix sockets (e.g. ControlSocket). If the option is set to 1, make
+ the control socket readable and writable by the default GID. (Default: 0)
+
**HashedControlPassword** __hashed_password__::
Don't allow any connections on the control port except when the other
process knows the password whose one-way hash is __hashed_password__. You
diff --git a/src/common/compat.c b/src/common/compat.c
index ea7f9d7efc..fc066da681 100644
--- a/src/common/compat.c
+++ b/src/common/compat.c
@@ -1467,6 +1467,45 @@ get_user_homedir(const char *username)
}
#endif
+/** Modify <b>fname</b> to contain the name of the directory */
+int
+get_parent_directory(char *fname)
+{
+ char *cp;
+ int at_end = 1;
+ tor_assert(fname);
+#ifdef MS_WINDOWS
+ /* If we start with, say, c:, then don't consider that the start of the path
+ */
+ if (fname[0] && fname[1] == ':') {
+ fname += 2;
+ }
+#endif
+ /* Now we want to remove all path-separators at the end of the string,
+ * and to remove the end of the string starting with the path separator
+ * before the last non-path-separator. In perl, this would be
+ * s#[/]*$##; s#/[^/]*$##;
+ * on a unixy platform.
+ */
+ cp = fname + strlen(fname);
+ at_end = 1;
+ while (--cp > fname) {
+ int is_sep = (*cp == '/'
+#ifdef MS_WINDOWS
+ || *cp == '\\'
+#endif
+ );
+ if (is_sep) {
+ *cp = '\0';
+ if (! at_end)
+ return 0;
+ } else {
+ at_end = 0;
+ }
+ }
+ return -1;
+}
+
/** Set *addr to the IP address (in dotted-quad notation) stored in c.
* Return 1 on success, 0 if c is badly formatted. (Like inet_aton(c,addr),
* but works on Windows and Solaris.)
diff --git a/src/common/compat.h b/src/common/compat.h
index af795ffba9..eff51ab30c 100644
--- a/src/common/compat.h
+++ b/src/common/compat.h
@@ -552,6 +552,8 @@ int switch_id(const char *user);
char *get_user_homedir(const char *username);
#endif
+int get_parent_directory(char *fname);
+
int spawn_func(void (*func)(void *), void *data);
void spawn_exit(void) ATTR_NORETURN;
diff --git a/src/common/container.c b/src/common/container.c
index 09d4bb131f..da44b7fe68 100644
--- a/src/common/container.c
+++ b/src/common/container.c
@@ -210,11 +210,30 @@ smartlist_string_isin_case(const smartlist_t *sl, const char *element)
int
smartlist_string_num_isin(const smartlist_t *sl, int num)
{
- char buf[16];
+ char buf[32]; /* long enough for 64-bit int, and then some. */
tor_snprintf(buf,sizeof(buf),"%d", num);
return smartlist_string_isin(sl, buf);
}
+/** Return true iff the two lists contain the same strings in the same
+ * order, or if they are both NULL. */
+int
+smartlist_strings_eq(const smartlist_t *sl1, const smartlist_t *sl2)
+{
+ if (sl1 == NULL)
+ return sl2 == NULL;
+ if (sl2 == NULL)
+ return 0;
+ if (smartlist_len(sl1) != smartlist_len(sl2))
+ return 0;
+ SMARTLIST_FOREACH(sl1, const char *, cp1, {
+ const char *cp2 = smartlist_get(sl2, cp1_sl_idx);
+ if (strcmp(cp1, cp2))
+ return 0;
+ });
+ return 1;
+}
+
/** Return true iff <b>sl</b> has some element E such that
* tor_memeq(E,<b>element</b>,DIGEST_LEN)
*/
diff --git a/src/common/container.h b/src/common/container.h
index b39d4ca07e..4a6eba789d 100644
--- a/src/common/container.h
+++ b/src/common/container.h
@@ -42,6 +42,8 @@ int smartlist_string_pos(const smartlist_t *, const char *elt) ATTR_PURE;
int smartlist_string_isin_case(const smartlist_t *sl, const char *element)
ATTR_PURE;
int smartlist_string_num_isin(const smartlist_t *sl, int num) ATTR_PURE;
+int smartlist_strings_eq(const smartlist_t *sl1, const smartlist_t *sl2)
+ ATTR_PURE;
int smartlist_digest_isin(const smartlist_t *sl, const char *element)
ATTR_PURE;
int smartlist_overlap(const smartlist_t *sl1, const smartlist_t *sl2)
@@ -259,7 +261,7 @@ char *smartlist_join_strings2(smartlist_t *sl, const char *join,
* Example use:
* SMARTLIST_FOREACH_JOIN(routerstatus_list, routerstatus_t *, rs,
* routerinfo_list, routerinfo_t *, ri,
- * tor_memcmp(rs->identity_digest, ri->identity_digest, 20),
+ * tor_memcmp(rs->identity_digest, ri->identity_digest, 20),
* log_info(LD_GENERAL,"No match for %s", ri->nickname)) {
* log_info(LD_GENERAL, "%s matches routerstatus %p", ri->nickname, rs);
* } SMARTLIST_FOREACH_JOIN_END(rs, ri);
diff --git a/src/common/di_ops.c b/src/common/di_ops.c
index c1e292fe2f..b22a58d1b1 100644
--- a/src/common/di_ops.c
+++ b/src/common/di_ops.c
@@ -3,18 +3,18 @@
/**
* \file di_ops.c
- * \brief Functions for data-independent operations
+ * \brief Functions for data-independent operations.
**/
#include "orconfig.h"
#include "di_ops.h"
/**
- * Timing-safe version of memcmp. As memcmp, compare the <b>sz</b> bytes
- * at <b>a</b> with the <b>sz</b> bytes at <b>, and returns less than 0 if the
- * bytes at <b>a</b> lexically precede those at <b>b</b>, 0 if the byte ranges
- * are equal, and greater than zero if the bytes at <b>a</b> lexically follow
- * those at <b>.
+ * Timing-safe version of memcmp. As memcmp, compare the <b>sz</b> bytes at
+ * <b>a</b> with the <b>sz</b> bytes at <b>b</b>, and return less than 0 if
+ * the bytes at <b>a</b> lexically precede those at <b>b</b>, 0 if the byte
+ * ranges are equal, and greater than zero if the bytes at <b>a</b> lexically
+ * follow those at <b>b</b>.
*
* This implementation differs from memcmp in that its timing behavior is not
* data-dependent: it should return in the same amount of time regardless of
@@ -85,7 +85,7 @@ tor_memcmp(const void *a, const void *b, size_t len)
/**
* Timing-safe memory comparison. Return true if the <b>sz</b> bytes at
- * <b>a</b> are the same as the <b>sz</b> bytes at <b>, and 0 otherwise.
+ * <b>a</b> are the same as the <b>sz</b> bytes at <b>b</b>, and 0 otherwise.
*
* This implementation differs from !memcmp(a,b,sz) in that its timing
* behavior is not data-dependent: it should return in the same amount of time
diff --git a/src/common/di_ops.h b/src/common/di_ops.h
index 4a212b0ca2..fa7d86806a 100644
--- a/src/common/di_ops.h
+++ b/src/common/di_ops.h
@@ -28,3 +28,4 @@ int tor_memeq(const void *a, const void *b, size_t sz);
#define fast_memneq(a,b,c) (0!=memcmp((a),(b),(c)))
#endif
+
diff --git a/src/common/util.c b/src/common/util.c
index 86f4141674..1bb116b212 100644
--- a/src/common/util.c
+++ b/src/common/util.c
@@ -30,6 +30,7 @@
#else
#include <dirent.h>
#include <pwd.h>
+#include <grp.h>
#endif
/* math.h needs this on Linux */
@@ -1664,17 +1665,25 @@ file_status(const char *fname)
return FN_ERROR;
}
-/** Check whether dirname exists and is private. If yes return 0. If
- * it does not exist, and check==CPD_CREATE is set, try to create it
+/** Check whether <b>dirname</b> exists and is private. If yes return 0. If
+ * it does not exist, and <b>check</b>&CPD_CREATE is set, try to create it
* and return 0 on success. If it does not exist, and
- * check==CPD_CHECK, and we think we can create it, return 0. Else
- * return -1. */
+ * <b>check</b>&CPD_CHECK, and we think we can create it, return 0. Else
+ * return -1. If CPD_GROUP_OK is set, then it's okay if the directory
+ * is group-readable, but in all cases we create the directory mode 0700.
+ * If CPD_CHECK_MODE_ONLY is set, then we don't alter the directory permissions
+ * if they are too permissive: we just return -1.
+ */
int
check_private_dir(const char *dirname, cpd_check_t check)
{
int r;
struct stat st;
char *f;
+#ifndef MS_WINDOWS
+ int mask;
+#endif
+
tor_assert(dirname);
f = tor_strdup(dirname);
clean_name_for_stat(f);
@@ -1686,10 +1695,7 @@ check_private_dir(const char *dirname, cpd_check_t check)
strerror(errno));
return -1;
}
- if (check == CPD_NONE) {
- log_warn(LD_FS, "Directory %s does not exist.", dirname);
- return -1;
- } else if (check == CPD_CREATE) {
+ if (check & CPD_CREATE) {
log_info(LD_GENERAL, "Creating directory %s", dirname);
#if defined (MS_WINDOWS) && !defined (WINCE)
r = mkdir(dirname);
@@ -1701,6 +1707,9 @@ check_private_dir(const char *dirname, cpd_check_t check)
strerror(errno));
return -1;
}
+ } else if (!(check & CPD_CHECK)) {
+ log_warn(LD_FS, "Directory %s does not exist.", dirname);
+ return -1;
}
/* XXXX In the case where check==CPD_CHECK, we should look at the
* parent directory a little harder. */
@@ -1728,9 +1737,38 @@ check_private_dir(const char *dirname, cpd_check_t check)
tor_free(process_ownername);
return -1;
}
- if (st.st_mode & 0077) {
+ if ((check & CPD_GROUP_OK) && st.st_gid != getgid()) {
+ struct group *gr;
+ char *process_groupname = NULL;
+ gr = getgrgid(getgid());
+ process_groupname = gr ? tor_strdup(gr->gr_name) : tor_strdup("<unknown>");
+ gr = getgrgid(st.st_gid);
+
+ log_warn(LD_FS, "%s is not owned by this group (%s, %d) but by group "
+ "%s (%d). Are you running Tor as the wrong user?",
+ dirname, process_groupname, (int)getgid(),
+ gr ? gr->gr_name : "<unknown>", (int)st.st_gid);
+
+ tor_free(process_groupname);
+ return -1;
+ }
+ if (check & CPD_GROUP_OK) {
+ mask = 0027;
+ } else {
+ mask = 0077;
+ }
+ if (st.st_mode & mask) {
+ unsigned new_mode;
+ if (check & CPD_CHECK_MODE_ONLY) {
+ log_warn(LD_FS, "Permissions on directory %s are too permissive.",
+ dirname);
+ return -1;
+ }
log_warn(LD_FS, "Fixing permissions on directory %s", dirname);
- if (chmod(dirname, 0700)) {
+ new_mode = st.st_mode;
+ new_mode |= 0700; /* Owner should have rwx */
+ new_mode &= ~mask; /* Clear the other bits that we didn't want set...*/
+ if (chmod(dirname, new_mode)) {
log_warn(LD_FS, "Could not chmod directory %s: %s", dirname,
strerror(errno));
return -1;
diff --git a/src/common/util.h b/src/common/util.h
index 961b5875ad..f32709accd 100644
--- a/src/common/util.h
+++ b/src/common/util.h
@@ -286,7 +286,12 @@ file_status_t file_status(const char *filename);
/** Possible behaviors for check_private_dir() on encountering a nonexistent
* directory; see that function's documentation for details. */
-typedef enum { CPD_NONE, CPD_CREATE, CPD_CHECK } cpd_check_t;
+typedef unsigned int cpd_check_t;
+#define CPD_NONE 0
+#define CPD_CREATE 1
+#define CPD_CHECK 2
+#define CPD_GROUP_OK 4
+#define CPD_CHECK_MODE_ONLY 8
int check_private_dir(const char *dirname, cpd_check_t check);
#define OPEN_FLAGS_REPLACE (O_WRONLY|O_CREAT|O_TRUNC)
#define OPEN_FLAGS_APPEND (O_WRONLY|O_CREAT|O_APPEND)
diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c
index a9986d309c..860cd27567 100644
--- a/src/or/circuitbuild.c
+++ b/src/or/circuitbuild.c
@@ -4471,6 +4471,9 @@ typedef struct {
tor_addr_t addr;
/** TLS port for the bridge. */
uint16_t port;
+ /** Boolean: We are re-parsing our bridge list, and we are going to remove
+ * this one if we don't find it in the list of configured bridges. */
+ unsigned marked_for_removal : 1;
/** Expected identity digest, or all zero bytes if we don't know what the
* digest should be. */
char identity[DIGEST_LEN];
@@ -4479,11 +4482,39 @@ typedef struct {
} bridge_info_t;
/** A list of configured bridges. Whenever we actually get a descriptor
- * for one, we add it as an entry guard. */
+ * for one, we add it as an entry guard. Note that the order of bridges
+ * in this list does not necessarily correspond to the order of bridges
+ * in the torrc. */
static smartlist_t *bridge_list = NULL;
-/** Initialize the bridge list to empty, creating it if needed. */
+/** Mark every entry of the bridge list to be removed on our next call to
+ * sweep_bridge_list unless it has first been un-marked. */
+void
+mark_bridge_list(void)
+{
+ if (!bridge_list)
+ bridge_list = smartlist_create();
+ SMARTLIST_FOREACH(bridge_list, bridge_info_t *, b,
+ b->marked_for_removal = 1);
+}
+
+/** Remove every entry of the bridge list that was marked with
+ * mark_bridge_list if it has not subsequently been un-marked. */
void
+sweep_bridge_list(void)
+{
+ if (!bridge_list)
+ bridge_list = smartlist_create();
+ SMARTLIST_FOREACH_BEGIN(bridge_list, bridge_info_t *, b) {
+ if (b->marked_for_removal) {
+ SMARTLIST_DEL_CURRENT(bridge_list, b);
+ tor_free(b);
+ }
+ } SMARTLIST_FOREACH_END(b);
+}
+
+/** Initialize the bridge list to empty, creating it if needed. */
+static void
clear_bridge_list(void)
{
if (!bridge_list)
@@ -4496,7 +4527,8 @@ clear_bridge_list(void)
* (either by comparing keys if possible, else by comparing addr/port).
* Else return NULL. */
static bridge_info_t *
-get_configured_bridge_by_addr_port_digest(tor_addr_t *addr, uint16_t port,
+get_configured_bridge_by_addr_port_digest(const tor_addr_t *addr,
+ uint16_t port,
const char *digest)
{
if (!bridge_list)
@@ -4537,7 +4569,8 @@ routerinfo_is_a_configured_bridge(routerinfo_t *ri)
* If it was a bridge, and we still don't know its digest, record it.
*/
void
-learned_router_identity(tor_addr_t *addr, uint16_t port, const char *digest)
+learned_router_identity(const tor_addr_t *addr, uint16_t port,
+ const char *digest)
{
bridge_info_t *bridge =
get_configured_bridge_by_addr_port_digest(addr, port, digest);
@@ -4549,11 +4582,20 @@ learned_router_identity(tor_addr_t *addr, uint16_t port, const char *digest)
}
/** Remember a new bridge at <b>addr</b>:<b>port</b>. If <b>digest</b>
- * is set, it tells us the identity key too. */
+ * is set, it tells us the identity key too. If we already had the
+ * bridge in our list, unmark it, and don't actually add anything new. */
void
-bridge_add_from_config(const tor_addr_t *addr, uint16_t port, char *digest)
+bridge_add_from_config(const tor_addr_t *addr, uint16_t port,
+ const char *digest)
{
- bridge_info_t *b = tor_malloc_zero(sizeof(bridge_info_t));
+ bridge_info_t *b;
+
+ if ((b = get_configured_bridge_by_addr_port_digest(addr, port, digest))) {
+ b->marked_for_removal = 0;
+ return;
+ }
+
+ b = tor_malloc_zero(sizeof(bridge_info_t));
tor_addr_copy(&b->addr, addr);
b->port = port;
if (digest)
@@ -4561,6 +4603,7 @@ bridge_add_from_config(const tor_addr_t *addr, uint16_t port, char *digest)
b->fetch_status.schedule = DL_SCHED_BRIDGE;
if (!bridge_list)
bridge_list = smartlist_create();
+
smartlist_add(bridge_list, b);
}
diff --git a/src/or/circuitbuild.h b/src/or/circuitbuild.h
index af24931878..0e673e1c05 100644
--- a/src/or/circuitbuild.h
+++ b/src/or/circuitbuild.h
@@ -62,12 +62,13 @@ int getinfo_helper_entry_guards(control_connection_t *conn,
const char *question, char **answer,
const char **errmsg);
-void clear_bridge_list(void);
+void mark_bridge_list(void);
+void sweep_bridge_list(void);
int routerinfo_is_a_configured_bridge(routerinfo_t *ri);
-void
-learned_router_identity(tor_addr_t *addr, uint16_t port, const char *digest);
+void learned_router_identity(const tor_addr_t *addr, uint16_t port,
+ const char *digest);
void bridge_add_from_config(const tor_addr_t *addr, uint16_t port,
- char *digest);
+ const char *digest);
void retry_bridge_descriptor_fetch_directly(const char *digest);
void fetch_bridge_descriptors(or_options_t *options, time_t now);
void learned_bridge_descriptor(routerinfo_t *ri, int from_cache);
diff --git a/src/or/circuituse.c b/src/or/circuituse.c
index e68fb4fa82..7289aa5c11 100644
--- a/src/or/circuituse.c
+++ b/src/or/circuituse.c
@@ -1485,15 +1485,35 @@ link_apconn_to_circ(edge_connection_t *apconn, origin_circuit_t *circ,
}
}
-/** If an exit wasn't specifically chosen, save the history for future
- * use. */
+/** Return true iff <b>address</b> is matched by one of the entries in
+ * TrackHostExits. */
+int
+hostname_in_track_host_exits(or_options_t *options, const char *address)
+{
+ if (!options->TrackHostExits)
+ return 0;
+ SMARTLIST_FOREACH_BEGIN(options->TrackHostExits, const char *, cp) {
+ if (cp[0] == '.') { /* match end */
+ if (cp[1] == '\0' ||
+ !strcasecmpend(address, cp) ||
+ !strcasecmp(address, &cp[1]))
+ return 1;
+ } else if (strcasecmp(cp, address) == 0) {
+ return 1;
+ }
+ } SMARTLIST_FOREACH_END(cp);
+ return 0;
+}
+
+/** If an exit wasn't explicitly specified for <b>conn</b>, consider saving
+ * the exit that we *did* choose for use by future connections to
+ * <b>conn</b>'s destination.
+ */
static void
consider_recording_trackhost(edge_connection_t *conn, origin_circuit_t *circ)
{
- int found_needle = 0;
or_options_t *options = get_options();
- size_t len;
- char *new_address;
+ char *new_address = NULL;
char fp[HEX_DIGEST_LEN+1];
/* Search the addressmap for this conn's destination. */
@@ -1503,18 +1523,8 @@ consider_recording_trackhost(edge_connection_t *conn, origin_circuit_t *circ)
options->TrackHostExitsExpire))
return; /* nothing to track, or already mapped */
- SMARTLIST_FOREACH(options->TrackHostExits, const char *, cp, {
- if (cp[0] == '.') { /* match end */
- if (cp[1] == '\0' ||
- !strcasecmpend(conn->socks_request->address, cp) ||
- !strcasecmp(conn->socks_request->address, &cp[1]))
- found_needle = 1;
- } else if (strcasecmp(cp, conn->socks_request->address) == 0) {
- found_needle = 1;
- }
- });
-
- if (!found_needle || !circ->build_state->chosen_exit)
+ if (!hostname_in_track_host_exits(options, conn->socks_request->address) ||
+ !circ->build_state->chosen_exit)
return;
/* write down the fingerprint of the chosen exit, not the nickname,
@@ -1523,12 +1533,7 @@ consider_recording_trackhost(edge_connection_t *conn, origin_circuit_t *circ)
circ->build_state->chosen_exit->identity_digest, DIGEST_LEN);
/* Add this exit/hostname pair to the addressmap. */
- len = strlen(conn->socks_request->address) + 1 /* '.' */ +
- strlen(fp) + 1 /* '.' */ +
- strlen("exit") + 1 /* '\0' */;
- new_address = tor_malloc(len);
-
- tor_snprintf(new_address, len, "%s.%s.exit",
+ tor_asprintf(&new_address, "%s.%s.exit",
conn->socks_request->address, fp);
addressmap_register(conn->socks_request->address, new_address,
diff --git a/src/or/circuituse.h b/src/or/circuituse.h
index 9f393ab378..bfeaea20dc 100644
--- a/src/or/circuituse.h
+++ b/src/or/circuituse.h
@@ -51,5 +51,7 @@ int connection_ap_handshake_attach_chosen_circuit(edge_connection_t *conn,
crypt_path_t *cpath);
int connection_ap_handshake_attach_circuit(edge_connection_t *conn);
+int hostname_in_track_host_exits(or_options_t *options, const char *address);
+
#endif
diff --git a/src/or/config.c b/src/or/config.c
index a7ff28f462..614fc48c3e 100644
--- a/src/or/config.c
+++ b/src/or/config.c
@@ -209,6 +209,7 @@ static config_var_t _option_vars[] = {
V(ControlPortFileGroupReadable,BOOL, "0"),
V(ControlPortWriteToFile, FILENAME, NULL),
V(ControlSocket, LINELIST, NULL),
+ V(ControlSocketsGroupWritable, BOOL, "0"),
V(CookieAuthentication, BOOL, "0"),
V(CookieAuthFileGroupReadable, BOOL, "0"),
V(CookieAuthFile, STRING, NULL),
@@ -952,9 +953,15 @@ options_act_reversible(or_options_t *old_options, char **msg)
}
#ifndef HAVE_SYS_UN_H
- if (options->ControlSocket) {
- *msg = tor_strdup("Unix domain sockets (ControlSocket) not supported"
- " on this OS/with this build.");
+ if (options->ControlSocket || options->ControlSocketsGroupWritable) {
+ *msg = tor_strdup("Unix domain sockets (ControlSocket) not supported "
+ "on this OS/with this build.");
+ goto rollback;
+ }
+#else
+ if (options->ControlSocketsGroupWritable && !options->ControlSocket) {
+ *msg = tor_strdup("Setting ControlSocketGroupWritable without setting"
+ "a ControlSocket makes no sense.");
goto rollback;
}
#endif
@@ -1172,7 +1179,7 @@ options_act(or_options_t *old_options)
return -1;
if (options->Bridges) {
- clear_bridge_list();
+ mark_bridge_list();
for (cl = options->Bridges; cl; cl = cl->next) {
if (parse_bridge_line(cl->value, 0)<0) {
log_warn(LD_BUG,
@@ -1180,6 +1187,7 @@ options_act(or_options_t *old_options)
return -1;
}
}
+ sweep_bridge_list();
}
if (running_tor && rend_config_services(options, 0)<0) {
@@ -1264,6 +1272,8 @@ options_act(or_options_t *old_options)
/* Check for transitions that need action. */
if (old_options) {
+ int revise_trackexithosts = 0;
+ int revise_automap_entries = 0;
if ((options->UseEntryGuards && !old_options->UseEntryGuards) ||
!routerset_equal(old_options->ExcludeNodes,options->ExcludeNodes) ||
!routerset_equal(old_options->ExcludeExitNodes,
@@ -1276,9 +1286,31 @@ options_act(or_options_t *old_options)
"excluded node lists. Abandoning previous circuits.");
circuit_mark_all_unused_circs();
circuit_expire_all_dirty_circs();
+ revise_trackexithosts = 1;
+ }
+
+ if (!smartlist_strings_eq(old_options->TrackHostExits,
+ options->TrackHostExits))
+ revise_trackexithosts = 1;
+
+ if (revise_trackexithosts)
addressmap_clear_excluded_trackexithosts(options);
+
+ if (!options->AutomapHostsOnResolve) {
+ if (old_options->AutomapHostsOnResolve)
+ revise_automap_entries = 1;
+ } else {
+ if (!smartlist_strings_eq(old_options->AutomapHostsSuffixes,
+ options->AutomapHostsSuffixes))
+ revise_automap_entries = 1;
+ else if (!opt_streq(old_options->VirtualAddrNetwork,
+ options->VirtualAddrNetwork))
+ revise_automap_entries = 1;
}
+ if (revise_automap_entries)
+ addressmap_clear_invalid_automaps(options);
+
/* How long should we delay counting bridge stats after becoming a bridge?
* We use this so we don't count people who used our bridge thinking it is
* a relay. If you change this, don't forget to change the log message
diff --git a/src/or/connection.c b/src/or/connection.c
index 01b533d9b5..b7d6fe408d 100644
--- a/src/or/connection.c
+++ b/src/or/connection.c
@@ -853,6 +853,43 @@ warn_too_many_conns(void)
}
}
+#ifdef HAVE_SYS_UN_H
+/** Check whether we should be willing to open an AF_UNIX socket in
+ * <b>path</b>. Return 0 if we should go ahead and -1 if we shouldn't. */
+static int
+check_location_for_unix_socket(or_options_t *options, const char *path)
+{
+ int r = -1;
+ char *p = tor_strdup(path);
+ cpd_check_t flags = CPD_CHECK_MODE_ONLY;
+ if (get_parent_directory(p)<0)
+ goto done;
+
+ if (options->ControlSocketsGroupWritable)
+ flags |= CPD_GROUP_OK;
+
+ if (check_private_dir(p, flags) < 0) {
+ char *escpath, *escdir;
+ escpath = esc_for_log(path);
+ escdir = esc_for_log(p);
+ log_warn(LD_GENERAL, "Before Tor can create a control socket in %s, the "
+ "directory %s needs to exist, and to be accessible only by the "
+ "user%s account that is running Tor. (On some Unix systems, "
+ "anybody who can list a socket can conect to it, so Tor is "
+ "being careful.)", escpath, escdir,
+ options->ControlSocketsGroupWritable ? " and group" : "");
+ tor_free(escpath);
+ tor_free(escdir);
+ goto done;
+ }
+
+ r = 0;
+ done:
+ tor_free(p);
+ return r;
+}
+#endif
+
/** Bind a new non-blocking socket listening to the socket described
* by <b>listensockaddr</b>.
*
@@ -947,6 +984,9 @@ connection_create_listener(const struct sockaddr *listensockaddr,
* and listeners at the same time */
tor_assert(type == CONN_TYPE_CONTROL_LISTENER);
+ if (check_location_for_unix_socket(get_options(), address) < 0)
+ goto err;
+
log_notice(LD_NET, "Opening %s on %s",
conn_type_to_string(type), address);
@@ -966,6 +1006,15 @@ connection_create_listener(const struct sockaddr *listensockaddr,
tor_socket_strerror(tor_socket_errno(s)));
goto err;
}
+ if (get_options()->ControlSocketsGroupWritable) {
+ /* We need to use chmod; fchmod doesn't work on sockets on all
+ * platforms. */
+ if (chmod(address, 0660) < 0) {
+ log_warn(LD_FS,"Unable to make %s group-writable.", address);
+ tor_close_socket(s);
+ goto err;
+ }
+ }
if (listen(s,SOMAXCONN) < 0) {
log_warn(LD_NET, "Could not listen on %s: %s", address,
diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c
index 037920b688..7828f16386 100644
--- a/src/or/connection_edge.c
+++ b/src/or/connection_edge.c
@@ -810,7 +810,8 @@ clear_trackexithost_mappings(const char *exitname)
}
/** Remove all TRACKEXIT mappings from the addressmap for which the target
- * host is unknown or no longer allowed. */
+ * host is unknown or no longer allowed, or for which the source address
+ * is no longer in trackexithosts. */
void
addressmap_clear_excluded_trackexithosts(or_options_t *options)
{
@@ -851,7 +852,8 @@ addressmap_clear_excluded_trackexithosts(or_options_t *options)
tor_free(nodename);
if (!ri ||
(allow_nodes && !routerset_contains_router(allow_nodes, ri)) ||
- routerset_contains_router(exclude_nodes, ri)) {
+ routerset_contains_router(exclude_nodes, ri) ||
+ !hostname_in_track_host_exits(options, address)) {
/* We don't know this one, or we want to be rid of it. */
addressmap_ent_remove(address, ent);
MAP_DEL_CURRENT(address);
@@ -859,6 +861,49 @@ addressmap_clear_excluded_trackexithosts(or_options_t *options)
} STRMAP_FOREACH_END;
}
+/** Remove all AUTOMAP mappings from the addressmap for which the
+ * source address no longer matches AutomapHostsSuffixes, which is
+ * no longer allowed by AutomapHostsOnResolve, or for which the
+ * target address is no longer in the virtual network. */
+void
+addressmap_clear_invalid_automaps(or_options_t *options)
+{
+ int clear_all = !options->AutomapHostsOnResolve;
+ const smartlist_t *suffixes = options->AutomapHostsSuffixes;
+
+ if (!addressmap)
+ return;
+
+ if (!suffixes)
+ clear_all = 1; /* This should be impossible, but let's be sure. */
+
+ STRMAP_FOREACH_MODIFY(addressmap, src_address, addressmap_entry_t *, ent) {
+ int remove = clear_all;
+ if (ent->source != ADDRMAPSRC_AUTOMAP)
+ continue; /* not an automap mapping. */
+
+ if (!remove) {
+ int suffix_found = 0;
+ SMARTLIST_FOREACH(suffixes, const char *, suffix, {
+ if (!strcasecmpend(src_address, suffix)) {
+ suffix_found = 1;
+ break;
+ }
+ });
+ if (!suffix_found)
+ remove = 1;
+ }
+
+ if (!remove && ! address_is_in_virtual_range(ent->new_address))
+ remove = 1;
+
+ if (remove) {
+ addressmap_ent_remove(src_address, ent);
+ MAP_DEL_CURRENT(src_address);
+ }
+ } STRMAP_FOREACH_END;
+}
+
/** Remove all entries from the addressmap that were set via the
* configuration file or the command line. */
void
@@ -1370,7 +1415,7 @@ addressmap_register_virtual_address(int type, char *new_address)
log_info(LD_APP, "Registering map from %s to %s", *addrp, new_address);
if (vent_needs_to_be_added)
strmap_set(virtaddress_reversemap, new_address, vent);
- addressmap_register(*addrp, new_address, 2, ADDRMAPSRC_CONTROLLER);
+ addressmap_register(*addrp, new_address, 2, ADDRMAPSRC_AUTOMAP);
#if 0
{
diff --git a/src/or/connection_edge.h b/src/or/connection_edge.h
index 70d0dd2713..8ba2fafd08 100644
--- a/src/or/connection_edge.h
+++ b/src/or/connection_edge.h
@@ -62,6 +62,7 @@ int address_is_invalid_destination(const char *address, int client);
void addressmap_init(void);
void addressmap_clear_excluded_trackexithosts(or_options_t *options);
+void addressmap_clear_invalid_automaps(or_options_t *options);
void addressmap_clean(time_t now);
void addressmap_clear_configured(void);
void addressmap_clear_transient(void);
diff --git a/src/or/directory.c b/src/or/directory.c
index 4c26671c70..347ed42cb8 100644
--- a/src/or/directory.c
+++ b/src/or/directory.c
@@ -279,6 +279,8 @@ directory_post_to_dirservers(uint8_t dir_purpose, uint8_t router_purpose,
int post_via_tor;
smartlist_t *dirservers = router_get_trusted_dir_servers();
int found = 0;
+ const int exclude_self = (dir_purpose == DIR_PURPOSE_UPLOAD_VOTE ||
+ dir_purpose == DIR_PURPOSE_UPLOAD_SIGNATURES);
tor_assert(dirservers);
/* This tries dirservers which we believe to be down, but ultimately, that's
* harmless, and we may as well err on the side of getting things uploaded.
@@ -291,6 +293,9 @@ directory_post_to_dirservers(uint8_t dir_purpose, uint8_t router_purpose,
if ((type & ds->type) == 0)
continue;
+ if (exclude_self && router_digest_is_me(ds->digest))
+ continue;
+
if (options->ExcludeNodes && options->StrictNodes &&
routerset_contains_routerstatus(options->ExcludeNodes, rs)) {
log_warn(LD_DIR, "Wanted to contact authority '%s' for %s, but "
diff --git a/src/or/dirvote.c b/src/or/dirvote.c
index dd156bd9d9..96e3df5cec 100644
--- a/src/or/dirvote.c
+++ b/src/or/dirvote.c
@@ -397,8 +397,9 @@ compare_vote_rs(const vote_routerstatus_t *a, const vote_routerstatus_t *b)
if ((r = fast_memcmp(a->status.identity_digest, b->status.identity_digest,
DIGEST_LEN)))
return r;
- if ((r = fast_memcmp(a->status.descriptor_digest, b->status.descriptor_digest,
- DIGEST_LEN)))
+ if ((r = fast_memcmp(a->status.descriptor_digest,
+ b->status.descriptor_digest,
+ DIGEST_LEN)))
return r;
if ((r = (int)(b->status.published_on - a->status.published_on)))
return r;
@@ -1705,7 +1706,8 @@ networkstatus_compute_consensus(smartlist_t *votes,
if (index[v_sl_idx] < size[v_sl_idx]) {
rs = smartlist_get(v->routerstatus_list, index[v_sl_idx]);
if (!lowest_id ||
- fast_memcmp(rs->status.identity_digest, lowest_id, DIGEST_LEN) < 0)
+ fast_memcmp(rs->status.identity_digest,
+ lowest_id, DIGEST_LEN) < 0)
lowest_id = rs->status.identity_digest;
}
});
@@ -1769,7 +1771,7 @@ networkstatus_compute_consensus(smartlist_t *votes,
rs = compute_routerstatus_consensus(matching_descs, consensus_method,
microdesc_digest);
/* Copy bits of that into rs_out. */
- tor_assert(fast_memeq(lowest_id, rs->status.identity_digest, DIGEST_LEN));
+ tor_assert(fast_memeq(lowest_id, rs->status.identity_digest,DIGEST_LEN));
memcpy(rs_out.identity_digest, lowest_id, DIGEST_LEN);
memcpy(rs_out.descriptor_digest, rs->status.descriptor_digest,
DIGEST_LEN);
@@ -2211,7 +2213,8 @@ networkstatus_add_detached_signatures(networkstatus_t *target,
}
for (alg = DIGEST_SHA1; alg < N_DIGEST_ALGORITHMS; ++alg) {
if (!tor_mem_is_zero(digests->d[alg], DIGEST256_LEN)) {
- if (fast_memeq(target->digests.d[alg], digests->d[alg], DIGEST256_LEN)) {
+ if (fast_memeq(target->digests.d[alg], digests->d[alg],
+ DIGEST256_LEN)) {
++n_matches;
} else {
*msg_out = "Mismatched digest.";
diff --git a/src/or/main.c b/src/or/main.c
index 15682d5400..d700f0e7a8 100644
--- a/src/or/main.c
+++ b/src/or/main.c
@@ -1417,7 +1417,6 @@ do_hup(void)
router_reset_warnings();
routerlist_reset_warnings();
- addressmap_clear_transient();
/* first, reload config variables, in case they've changed */
if (options->ReloadTorrcOnSIGHUP) {
/* no need to provide argc/v, they've been cached in init_from_config */
diff --git a/src/or/or.h b/src/or/or.h
index a73d98ab74..b9d8319ba5 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -2445,6 +2445,7 @@ typedef struct {
int ControlPort; /**< Port to listen on for control connections. */
config_line_t *ControlSocket; /**< List of Unix Domain Sockets to listen on
* for control connections. */
+ int ControlSocketsGroupWritable; /**< Boolean: Are control sockets g+rw? */
int DirPort; /**< Port to listen on for directory connections. */
int DNSPort; /**< Port to listen on for DNS requests. */
int AssumeReachable; /**< Whether to publish our descriptor regardless. */
@@ -3150,6 +3151,9 @@ typedef enum setopt_err_t {
typedef enum {
/** We're remapping this address because the controller told us to. */
ADDRMAPSRC_CONTROLLER,
+ /** We're remapping this address because of an AutomapHostsOnResolve
+ * configuration. */
+ ADDRMAPSRC_AUTOMAP,
/** We're remapping this address because our configuration (via torrc, the
* command line, or a SETCONF command) told us to. */
ADDRMAPSRC_TORRC,
diff --git a/src/or/routerlist.c b/src/or/routerlist.c
index 6c649ab526..a3d9b78ee7 100644
--- a/src/or/routerlist.c
+++ b/src/or/routerlist.c
@@ -2332,8 +2332,8 @@ router_get_by_nickname(const char *nickname, int warn_if_unnamed)
if (n_matches <= 1 || router->is_running)
best_match = router;
} else if (maybedigest &&
- tor_memeq(digest, router->cache_info.identity_digest, DIGEST_LEN)
- ) {
+ tor_memeq(digest, router->cache_info.identity_digest,
+ DIGEST_LEN)) {
if (router_hex_digest_matches(router, nickname))
return router;
/* If we reach this point, we have a ID=name syntax that matches the
@@ -5063,8 +5063,9 @@ routerinfo_incompatible_with_extrainfo(routerinfo_t *ri, extrainfo_t *ei,
/* The identity must match exactly to have been generated at the same time
* by the same router. */
- if (tor_memneq(ri->cache_info.identity_digest, ei->cache_info.identity_digest,
- DIGEST_LEN)) {
+ if (tor_memneq(ri->cache_info.identity_digest,
+ ei->cache_info.identity_digest,
+ DIGEST_LEN)) {
if (msg) *msg = "Extrainfo nickname or identity did not match routerinfo";
goto err; /* different servers */
}
@@ -5758,8 +5759,6 @@ int
hid_serv_acting_as_directory(void)
{
routerinfo_t *me = router_get_my_routerinfo();
- networkstatus_t *c;
- routerstatus_t *rs;
if (!me)
return 0;
if (!get_options()->HidServDirectoryV2) {
@@ -5767,22 +5766,6 @@ hid_serv_acting_as_directory(void)
"because we have not been configured as such.");
return 0;
}
- if (!(c = networkstatus_get_latest_consensus())) {
- log_info(LD_REND, "There's no consensus, so I can't tell if I'm a hidden "
- "service directory");
- return 0;
- }
- rs = networkstatus_vote_find_entry(c, me->cache_info.identity_digest);
- if (!rs) {
- log_info(LD_REND, "We're not listed in the consensus, so we're not "
- "being a hidden service directory.");
- return 0;
- }
- if (!rs->is_hs_dir) {
- log_info(LD_REND, "We're not listed as a hidden service directory in "
- "the consensus, so we won't be one.");
- return 0;
- }
return 1;
}
diff --git a/src/test/test_util.c b/src/test/test_util.c
index 0da45df499..23cd059cf7 100644
--- a/src/test/test_util.c
+++ b/src/test/test_util.c
@@ -1195,6 +1195,35 @@ test_util_listdir(void *ptr)
}
}
+static void
+test_util_parent_dir(void *ptr)
+{
+ char *cp;
+ (void)ptr;
+
+#define T(input,expect_ok,output) \
+ do { \
+ int ok; \
+ cp = tor_strdup(input); \
+ ok = get_parent_directory(cp); \
+ tt_int_op(ok, ==, expect_ok); \
+ if (ok==0) \
+ tt_str_op(cp, ==, output); \
+ tor_free(cp); \
+ } while (0);
+
+ T("/home/wombat/knish", 0, "/home/wombat");
+ T("/home/wombat/knish/", 0, "/home/wombat");
+ T("./home/wombat/knish/", 0, "./home/wombat");
+ T("./wombat", 0, ".");
+ T("", -1, "");
+ T("/", -1, "");
+ T("////", -1, "");
+
+ done:
+ tor_free(cp);
+}
+
#ifdef MS_WINDOWS
static void
test_util_load_win_lib(void *ptr)
@@ -1286,6 +1315,7 @@ struct testcase_t util_tests[] = {
UTIL_TEST(find_str_at_start_of_line, 0),
UTIL_TEST(asprintf, 0),
UTIL_TEST(listdir, 0),
+ UTIL_TEST(parent_dir, 0),
#ifdef MS_WINDOWS
UTIL_TEST(load_win_lib, 0),
#endif