Merge branch 'bug14451_026_v1'

This commit is contained in:
Nick Mathewson 2015-01-29 15:16:15 -05:00
commit a87ea9b1c6
9 changed files with 123 additions and 67 deletions

View File

@ -1,9 +1,12 @@
o Major features (security)
- Implementation of SocksSocket option - SocksSocket implements a SOCKS
- Implementation of an AF_UNIX socket option to implement a SOCKS
proxy reachable by Unix Domain Socket. This allows client applications to
communicate with Tor without having the ability to create AF_INET or
AF_INET6 family sockets. If an application has permission to create a socket
with AF_UNIX, it may directly communicate with Tor as if it were an other
SOCKS proxy. This should allow high risk applications to be entirely prevented
from connecting directly with TCP/IP, they will be able to only connect to the
internet through AF_UNIX and only through Tor. Closes ticket 12585.
internet through AF_UNIX and only through Tor.
To create a socket of this type, use the syntax "unix:/path/to/socket".
Closes ticket 12585.

7
changes/bug14451 Normal file
View File

@ -0,0 +1,7 @@
o Minor features:
- ControlPort now supports the unix:/path/to/dir syntax as an alternative
to the ControlSocket option, for consistency with SocksPort and
hidden services. Closes ticket 14451.

View File

@ -273,7 +273,7 @@ GENERAL OPTIONS
all sockets will be set to this limit. Must be a value between 2048 and
262144, in 1024 byte increments. Default of 8192 is recommended.
[[ControlPort]] **ControlPort** __PORT__|**auto**::
[[ControlPort]] **ControlPort** __PORT__|**unix:**__path__|**auto**::
If set, Tor will accept connections on this port and allow those
connections to control the Tor process using the Tor Control Protocol
(described in control-spec.txt). Note: unless you also specify one or
@ -483,10 +483,6 @@ GENERAL OPTIONS
in accordance to RFC 1929. Both username and password must be between 1 and
255 characters.
[[SocksSocket]] **SocksSocket** __Path__ [_flags_] [_isolation flags_]::
Like SocksPort, but listens on a Unix domain socket, rather than a TCP
socket. '0' disables SocksSocket (Unix and Unix-like systems only.)
[[SocksSocketsGroupWritable]] **SocksSocketsGroupWritable** **0**|**1**::
If this option is set to 0, don't allow the filesystem group to read and
write unix sockets (e.g. SocksSocket). If the option is set to 1, make
@ -957,7 +953,7 @@ The following options are useful only for clients (that is, if
the same circuit. Currently, two addresses are "too close" if they lie in
the same /16 range. (Default: 1)
[[SOCKSPort]] **SOCKSPort** \['address':]__port__|**auto** [_flags_] [_isolation flags_]::
[[SOCKSPort]] **SOCKSPort** \['address':]__port__|**unix:**__path__|**auto** [_flags_] [_isolation flags_]::
Open this port to listen for connections from SOCKS-speaking
applications. Set this to 0 if you don't want to allow application
connections via SOCKS. Set it to "auto" to have Tor pick a port for

View File

@ -68,6 +68,9 @@
/* From main.c */
extern int quiet_level;
/* Prefix used to indicate a Unix socket in a FooPort configuration. */
static const char unix_socket_prefix[] = "unix:";
/** A list of abbreviations and aliases to map command-line options, obsolete
* option names, or alternative option names, to their current values. */
static config_abbrev_t option_abbrevs_[] = {
@ -200,7 +203,6 @@ static config_var_t option_vars_[] = {
V(ControlPortWriteToFile, FILENAME, NULL),
V(ControlSocket, LINELIST, NULL),
V(ControlSocketsGroupWritable, BOOL, "0"),
V(SocksSocket, LINELIST, NULL),
V(SocksSocketsGroupWritable, BOOL, "0"),
V(CookieAuthentication, BOOL, "0"),
V(CookieAuthFileGroupReadable, BOOL, "0"),
@ -1050,20 +1052,6 @@ options_act_reversible(const or_options_t *old_options, char **msg)
}
#endif
#ifndef HAVE_SYS_UN_H
if (options->SocksSocket || options->SocksSocketsGroupWritable) {
*msg = tor_strdup("Unix domain sockets (SocksSocket) not supported "
"on this OS/with this build.");
goto rollback;
}
#else
if (options->SocksSocketsGroupWritable && !options->SocksSocket) {
*msg = tor_strdup("Setting SocksSocketGroupWritable without setting"
"a SocksSocket makes no sense.");
goto rollback;
}
#endif
if (running_tor) {
int n_ports=0;
/* We need to set the connection limit before we can open the listeners. */
@ -5620,6 +5608,55 @@ warn_nonlocal_controller_ports(smartlist_t *ports, unsigned forbid)
#define CL_PORT_TAKES_HOSTNAMES (1u<<5)
#define CL_PORT_IS_UNIXSOCKET (1u<<6)
#ifdef HAVE_SYS_UN_H
/** Parse the given <b>addrport</b> and set <b>path_out</b> if a Unix socket
* path is found. Return 0 on success. On error, a negative value is
* returned, -ENOENT if no Unix statement found, -EINVAL if the socket path
* is empty and -ENOSYS if AF_UNIX is not supported (see function in the
* #else statement below). */
int
config_parse_unix_port(const char *addrport, char **path_out)
{
tor_assert(path_out);
tor_assert(addrport);
if (strcmpstart(addrport, unix_socket_prefix)) {
/* Not a Unix socket path. */
return -ENOENT;
}
if (strlen(addrport + strlen(unix_socket_prefix)) == 0) {
/* Empty socket path, not very usable. */
return -EINVAL;
}
*path_out = tor_strdup(addrport + strlen(unix_socket_prefix));
return 0;
}
#else /* defined(HAVE_SYS_UN_H) */
int
config_parse_unix_port(const char *addrport, char **path_out)
{
tor_assert(path_out);
tor_assert(addrport);
if (strcmpstart(addrport, unix_socket_prefix)) {
/* Not a Unix socket path. */
return -ENOENT;
}
log_warn(LD_CONFIG,
"Port configuration %s is for an AF_UNIX socket, but we have no"
"support available on this platform",
escaped(addrport));
return -ENOSYS;
}
#endif /* defined(HAVE_SYS_UN_H) */
/**
* Parse port configuration for a single port type.
*
@ -5681,6 +5718,7 @@ parse_port_config(smartlist_t *out,
const unsigned takes_hostnames = flags & CL_PORT_TAKES_HOSTNAMES;
const unsigned is_unix_socket = flags & CL_PORT_IS_UNIXSOCKET;
int got_zero_port=0, got_nonzero_port=0;
char *unix_socket_path = NULL;
/* FooListenAddress is deprecated; let's make it work like it used to work,
* though. */
@ -5785,7 +5823,7 @@ parse_port_config(smartlist_t *out,
for (; ports; ports = ports->next) {
tor_addr_t addr;
int port;
int port, ret;
int sessiongroup = SESSION_GROUP_UNSET;
unsigned isolation = ISO_DEFAULT;
int prefer_no_auth = 0;
@ -5814,8 +5852,26 @@ parse_port_config(smartlist_t *out,
/* Now parse the addr/port value */
addrport = smartlist_get(elts, 0);
if (is_unix_socket) {
/* leave it as it is. */
/* Let's start to check if it's a Unix socket path. */
ret = config_parse_unix_port(addrport, &unix_socket_path);
if (ret < 0 && ret != -ENOENT) {
if (ret == -EINVAL) {
log_warn(LD_CONFIG, "Empty Unix socket path.");
}
goto err;
}
if (unix_socket_path &&
! conn_listener_type_supports_af_unix(listener_type)) {
log_warn(LD_CONFIG, "%sPort does not support unix sockets", portname);
goto err;
}
if (unix_socket_path) {
port = 1;
} else if (is_unix_socket) {
unix_socket_path = tor_strdup(addrport);
if (!strcmp(addrport, "0"))
port = 0;
else
@ -6005,12 +6061,13 @@ parse_port_config(smartlist_t *out,
}
if (out && port) {
size_t namelen = is_unix_socket ? strlen(addrport) : 0;
size_t namelen = unix_socket_path ? strlen(unix_socket_path) : 0;
port_cfg_t *cfg = port_cfg_new(namelen);
if (is_unix_socket) {
if (unix_socket_path) {
tor_addr_make_unspec(&cfg->addr);
memcpy(cfg->unix_addr, addrport, strlen(addrport) + 1);
memcpy(cfg->unix_addr, unix_socket_path, namelen + 1);
cfg->is_unix_addr = 1;
tor_free(unix_socket_path);
} else {
tor_addr_copy(&cfg->addr, &addr);
cfg->port = port;
@ -6160,13 +6217,6 @@ parse_ports(or_options_t *options, int validate_only,
*msg = tor_strdup("Invalid ControlSocket configuration");
goto err;
}
if (parse_port_config(ports, options->SocksSocket, NULL,
"SocksSocket",
CONN_TYPE_AP_LISTENER, NULL, 0,
CL_PORT_IS_UNIXSOCKET) < 0) {
*msg = tor_strdup("Invalid SocksSocket configuration");
goto err;
}
}
if (! options->ClientOnly) {
if (parse_port_config(ports,
@ -6210,8 +6260,6 @@ parse_ports(or_options_t *options, int validate_only,
!! count_real_listeners(ports, CONN_TYPE_OR_LISTENER);
options->SocksPort_set =
!! count_real_listeners(ports, CONN_TYPE_AP_LISTENER);
options->SocksSocket_set =
!! count_real_listeners(ports, CONN_TYPE_AP_LISTENER);
options->TransPort_set =
!! count_real_listeners(ports, CONN_TYPE_AP_TRANS_LISTENER);
options->NATDPort_set =

View File

@ -113,6 +113,7 @@ int addressmap_register_auto(const char *from, const char *to,
time_t expires,
addressmap_entry_source_t addrmap_source,
const char **msg);
int config_parse_unix_port(const char *addrport, char **path_out);
/** Represents the information stored in a torrc Bridge line. */
typedef struct bridge_line_t {

View File

@ -449,6 +449,22 @@ connection_link_connections(connection_t *conn_a, connection_t *conn_b)
conn_b->linked_conn = conn_a;
}
/** Return true iff the provided connection listener type supports AF_UNIX
* sockets. */
int
conn_listener_type_supports_af_unix(int type)
{
/* For now only control ports or SOCKS ports can be Unix domain sockets
* and listeners at the same time */
switch (type) {
case CONN_TYPE_CONTROL_LISTENER:
case CONN_TYPE_AP_LISTENER:
return 1;
default:
return 0;
}
}
/** Deallocate memory used by <b>conn</b>. Deallocate its buffers if
* necessary, close its socket if necessary, and mark the directory as dirty
* if <b>conn</b> is an OR or OP connection.
@ -516,8 +532,7 @@ connection_free_(connection_t *conn)
if (conn->socket_family == AF_UNIX) {
/* For now only control and SOCKS ports can be Unix domain sockets
* and listeners at the same time */
tor_assert(conn->type == CONN_TYPE_CONTROL_LISTENER ||
conn->type == CONN_TYPE_AP_LISTENER);
tor_assert(conn_listener_type_supports_af_unix(conn->type));
if (unlink(conn->address) < 0 && errno != ENOENT) {
log_warn(LD_NET, "Could not unlink %s: %s", conn->address,
@ -1172,17 +1187,13 @@ connection_listener_new(const struct sockaddr *listensockaddr,
}
#ifdef HAVE_SYS_UN_H
/*
* AF_UNIX generic setup stuff (this covers both CONN_TYPE_CONTROL_LISTENER
* and CONN_TYPE_AP_LISTENER cases)
* AF_UNIX generic setup stuff
*/
} else if (listensockaddr->sa_family == AF_UNIX) {
/* We want to start reading for both AF_UNIX cases */
start_reading = 1;
/* For now only control ports or SOCKS ports can be Unix domain sockets
* and listeners at the same time */
tor_assert(type == CONN_TYPE_CONTROL_LISTENER ||
type == CONN_TYPE_AP_LISTENER);
tor_assert(conn_listener_type_supports_af_unix(type));
if (check_location_for_unix_socket(options, address,
(type == CONN_TYPE_CONTROL_LISTENER) ?
@ -1496,7 +1507,7 @@ connection_handle_listener_read(connection_t *conn, int new_type)
if (new_type == CONN_TYPE_AP && conn->socket_family == AF_UNIX) {
newconn->port = 0;
newconn->address = tor_strdup(conn->address);
log_info(LD_NET, "New SOCKS SocksSocket connection opened");
log_info(LD_NET, "New SOCKS AF_UNIX connection opened");
}
if (new_type == CONN_TYPE_CONTROL) {
log_notice(LD_CONTROL, "New control connection opened from %s.",

View File

@ -17,6 +17,7 @@
const char *conn_type_to_string(int type);
const char *conn_state_to_string(int type, int state);
int conn_listener_type_supports_af_unix(int type);
dir_connection_t *dir_connection_new(int socket_family);
or_connection_t *or_connection_new(int type, int socket_family);

View File

@ -3463,9 +3463,6 @@ typedef struct {
* for control connections. */
int ControlSocketsGroupWritable; /**< Boolean: Are control sockets g+rw? */
config_line_t *SocksSocket; /**< List of Unix Domain Sockets to listen on
* for SOCKS connections. */
int SocksSocketsGroupWritable; /**< Boolean: Are SOCKS sockets g+rw? */
/** Ports to listen on for directory connections. */
config_line_t *DirPort_lines;
@ -3489,7 +3486,6 @@ typedef struct {
*/
unsigned int ORPort_set : 1;
unsigned int SocksPort_set : 1;
unsigned int SocksSocket_set : 1;
unsigned int TransPort_set : 1;
unsigned int NATDPort_set : 1;
unsigned int ControlPort_set : 1;

View File

@ -341,7 +341,6 @@ parse_port_config(const char *string)
tor_addr_t addr;
const char *addrport;
rend_service_port_config_t *result = NULL;
const char *socket_prefix = "socket:";
unsigned int is_unix_addr = 0;
char *socket_path = NULL;
@ -365,25 +364,19 @@ parse_port_config(const char *string)
realport = virtport;
tor_addr_from_ipv4h(&addr, 0x7F000001u); /* 127.0.0.1 */
} else {
int ret;
addrport = smartlist_get(sl,1);
/* If it starts with socket:, try to parse it as a socket path */
if (!strcmpstart(addrport, socket_prefix)) {
if (strlen(addrport + strlen(socket_prefix)) > 0) {
#ifdef HAVE_SYS_UN_H
is_unix_addr = 1;
socket_path = tor_strdup(addrport + strlen(socket_prefix));
#else
log_warn(LD_CONFIG,
"Hidden service port configuration %s is for an AF_UNIX "
"socket, but we have no support available on this platform",
escaped(addrport));
goto err;
#endif /* defined(HAVE_SYS_UN_H) */
} else {
ret = config_parse_unix_port(addrport, &socket_path);
if (ret < 0 && ret != ENOENT) {
if (ret == -EINVAL) {
log_warn(LD_CONFIG,
"Empty socket path in hidden service port configuration.");
goto err;
}
goto err;
}
if (socket_path) {
is_unix_addr = 1;
} else if (strchr(addrport, ':') || strchr(addrport, '.')) {
/* else try it as an IP:port pair if it has a : or . in it */
if (tor_addr_port_lookup(addrport, &addr, &p)<0) {