Merge remote-tracking branch 'origin/maint-0.2.2' into release-0.2.2
This commit is contained in:
commit
fd105e1048
|
@ -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.
|
|
@ -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.
|
|
@ -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.
|
||||
|
|
@ -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.
|
||||
|
|
@ -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.
|
|
@ -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.
|
|
@ -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.
|
||||
|
|
@ -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
|
||||
|
|
|
@ -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.)
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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)
|
||||
*/
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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();
|
||||
addressmap_clear_excluded_trackexithosts(options);
|
||||
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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 "
|
||||
|
|
|
@ -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.";
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue