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) 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 proxy reachable by Unix Domain Socket. This allows client applications to
communicate with Tor without having the ability to create AF_INET or 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 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 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 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 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 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. 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 If set, Tor will accept connections on this port and allow those
connections to control the Tor process using the Tor Control Protocol connections to control the Tor process using the Tor Control Protocol
(described in control-spec.txt). Note: unless you also specify one or (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 in accordance to RFC 1929. Both username and password must be between 1 and
255 characters. 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**:: [[SocksSocketsGroupWritable]] **SocksSocketsGroupWritable** **0**|**1**::
If this option is set to 0, don't allow the filesystem group to read and 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 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 circuit. Currently, two addresses are "too close" if they lie in
the same /16 range. (Default: 1) 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 Open this port to listen for connections from SOCKS-speaking
applications. Set this to 0 if you don't want to allow application 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 connections via SOCKS. Set it to "auto" to have Tor pick a port for

View file

@ -68,6 +68,9 @@
/* From main.c */ /* From main.c */
extern int quiet_level; 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 /** A list of abbreviations and aliases to map command-line options, obsolete
* option names, or alternative option names, to their current values. */ * option names, or alternative option names, to their current values. */
static config_abbrev_t option_abbrevs_[] = { static config_abbrev_t option_abbrevs_[] = {
@ -200,7 +203,6 @@ static config_var_t option_vars_[] = {
V(ControlPortWriteToFile, FILENAME, NULL), V(ControlPortWriteToFile, FILENAME, NULL),
V(ControlSocket, LINELIST, NULL), V(ControlSocket, LINELIST, NULL),
V(ControlSocketsGroupWritable, BOOL, "0"), V(ControlSocketsGroupWritable, BOOL, "0"),
V(SocksSocket, LINELIST, NULL),
V(SocksSocketsGroupWritable, BOOL, "0"), V(SocksSocketsGroupWritable, BOOL, "0"),
V(CookieAuthentication, BOOL, "0"), V(CookieAuthentication, BOOL, "0"),
V(CookieAuthFileGroupReadable, BOOL, "0"), V(CookieAuthFileGroupReadable, BOOL, "0"),
@ -1050,20 +1052,6 @@ options_act_reversible(const or_options_t *old_options, char **msg)
} }
#endif #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) { if (running_tor) {
int n_ports=0; int n_ports=0;
/* We need to set the connection limit before we can open the listeners. */ /* 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_TAKES_HOSTNAMES (1u<<5)
#define CL_PORT_IS_UNIXSOCKET (1u<<6) #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. * 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 takes_hostnames = flags & CL_PORT_TAKES_HOSTNAMES;
const unsigned is_unix_socket = flags & CL_PORT_IS_UNIXSOCKET; const unsigned is_unix_socket = flags & CL_PORT_IS_UNIXSOCKET;
int got_zero_port=0, got_nonzero_port=0; 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, /* FooListenAddress is deprecated; let's make it work like it used to work,
* though. */ * though. */
@ -5785,7 +5823,7 @@ parse_port_config(smartlist_t *out,
for (; ports; ports = ports->next) { for (; ports; ports = ports->next) {
tor_addr_t addr; tor_addr_t addr;
int port; int port, ret;
int sessiongroup = SESSION_GROUP_UNSET; int sessiongroup = SESSION_GROUP_UNSET;
unsigned isolation = ISO_DEFAULT; unsigned isolation = ISO_DEFAULT;
int prefer_no_auth = 0; int prefer_no_auth = 0;
@ -5814,8 +5852,26 @@ parse_port_config(smartlist_t *out,
/* Now parse the addr/port value */ /* Now parse the addr/port value */
addrport = smartlist_get(elts, 0); 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")) if (!strcmp(addrport, "0"))
port = 0; port = 0;
else else
@ -6005,12 +6061,13 @@ parse_port_config(smartlist_t *out,
} }
if (out && port) { 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); port_cfg_t *cfg = port_cfg_new(namelen);
if (is_unix_socket) { if (unix_socket_path) {
tor_addr_make_unspec(&cfg->addr); 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; cfg->is_unix_addr = 1;
tor_free(unix_socket_path);
} else { } else {
tor_addr_copy(&cfg->addr, &addr); tor_addr_copy(&cfg->addr, &addr);
cfg->port = port; cfg->port = port;
@ -6160,13 +6217,6 @@ parse_ports(or_options_t *options, int validate_only,
*msg = tor_strdup("Invalid ControlSocket configuration"); *msg = tor_strdup("Invalid ControlSocket configuration");
goto err; 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 (! options->ClientOnly) {
if (parse_port_config(ports, 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); !! count_real_listeners(ports, CONN_TYPE_OR_LISTENER);
options->SocksPort_set = options->SocksPort_set =
!! count_real_listeners(ports, CONN_TYPE_AP_LISTENER); !! count_real_listeners(ports, CONN_TYPE_AP_LISTENER);
options->SocksSocket_set =
!! count_real_listeners(ports, CONN_TYPE_AP_LISTENER);
options->TransPort_set = options->TransPort_set =
!! count_real_listeners(ports, CONN_TYPE_AP_TRANS_LISTENER); !! count_real_listeners(ports, CONN_TYPE_AP_TRANS_LISTENER);
options->NATDPort_set = options->NATDPort_set =

View file

@ -113,6 +113,7 @@ int addressmap_register_auto(const char *from, const char *to,
time_t expires, time_t expires,
addressmap_entry_source_t addrmap_source, addressmap_entry_source_t addrmap_source,
const char **msg); const char **msg);
int config_parse_unix_port(const char *addrport, char **path_out);
/** Represents the information stored in a torrc Bridge line. */ /** Represents the information stored in a torrc Bridge line. */
typedef struct bridge_line_t { 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; 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 /** Deallocate memory used by <b>conn</b>. Deallocate its buffers if
* necessary, close its socket if necessary, and mark the directory as dirty * necessary, close its socket if necessary, and mark the directory as dirty
* if <b>conn</b> is an OR or OP connection. * 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) { if (conn->socket_family == AF_UNIX) {
/* For now only control and SOCKS ports can be Unix domain sockets /* For now only control and SOCKS ports can be Unix domain sockets
* and listeners at the same time */ * and listeners at the same time */
tor_assert(conn->type == CONN_TYPE_CONTROL_LISTENER || tor_assert(conn_listener_type_supports_af_unix(conn->type));
conn->type == CONN_TYPE_AP_LISTENER);
if (unlink(conn->address) < 0 && errno != ENOENT) { if (unlink(conn->address) < 0 && errno != ENOENT) {
log_warn(LD_NET, "Could not unlink %s: %s", conn->address, 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 #ifdef HAVE_SYS_UN_H
/* /*
* AF_UNIX generic setup stuff (this covers both CONN_TYPE_CONTROL_LISTENER * AF_UNIX generic setup stuff
* and CONN_TYPE_AP_LISTENER cases)
*/ */
} else if (listensockaddr->sa_family == AF_UNIX) { } else if (listensockaddr->sa_family == AF_UNIX) {
/* We want to start reading for both AF_UNIX cases */ /* We want to start reading for both AF_UNIX cases */
start_reading = 1; start_reading = 1;
/* For now only control ports or SOCKS ports can be Unix domain sockets tor_assert(conn_listener_type_supports_af_unix(type));
* and listeners at the same time */
tor_assert(type == CONN_TYPE_CONTROL_LISTENER ||
type == CONN_TYPE_AP_LISTENER);
if (check_location_for_unix_socket(options, address, if (check_location_for_unix_socket(options, address,
(type == CONN_TYPE_CONTROL_LISTENER) ? (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) { if (new_type == CONN_TYPE_AP && conn->socket_family == AF_UNIX) {
newconn->port = 0; newconn->port = 0;
newconn->address = tor_strdup(conn->address); 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) { if (new_type == CONN_TYPE_CONTROL) {
log_notice(LD_CONTROL, "New control connection opened from %s.", 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_type_to_string(int type);
const char *conn_state_to_string(int type, int state); 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); dir_connection_t *dir_connection_new(int socket_family);
or_connection_t *or_connection_new(int type, 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. */ * for control connections. */
int ControlSocketsGroupWritable; /**< Boolean: Are control sockets g+rw? */ 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? */ int SocksSocketsGroupWritable; /**< Boolean: Are SOCKS sockets g+rw? */
/** Ports to listen on for directory connections. */ /** Ports to listen on for directory connections. */
config_line_t *DirPort_lines; config_line_t *DirPort_lines;
@ -3489,7 +3486,6 @@ typedef struct {
*/ */
unsigned int ORPort_set : 1; unsigned int ORPort_set : 1;
unsigned int SocksPort_set : 1; unsigned int SocksPort_set : 1;
unsigned int SocksSocket_set : 1;
unsigned int TransPort_set : 1; unsigned int TransPort_set : 1;
unsigned int NATDPort_set : 1; unsigned int NATDPort_set : 1;
unsigned int ControlPort_set : 1; unsigned int ControlPort_set : 1;

View file

@ -341,7 +341,6 @@ parse_port_config(const char *string)
tor_addr_t addr; tor_addr_t addr;
const char *addrport; const char *addrport;
rend_service_port_config_t *result = NULL; rend_service_port_config_t *result = NULL;
const char *socket_prefix = "socket:";
unsigned int is_unix_addr = 0; unsigned int is_unix_addr = 0;
char *socket_path = NULL; char *socket_path = NULL;
@ -365,25 +364,19 @@ parse_port_config(const char *string)
realport = virtport; realport = virtport;
tor_addr_from_ipv4h(&addr, 0x7F000001u); /* 127.0.0.1 */ tor_addr_from_ipv4h(&addr, 0x7F000001u); /* 127.0.0.1 */
} else { } else {
int ret;
addrport = smartlist_get(sl,1); addrport = smartlist_get(sl,1);
/* If it starts with socket:, try to parse it as a socket path */ ret = config_parse_unix_port(addrport, &socket_path);
if (!strcmpstart(addrport, socket_prefix)) { if (ret < 0 && ret != ENOENT) {
if (strlen(addrport + strlen(socket_prefix)) > 0) { if (ret == -EINVAL) {
#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 {
log_warn(LD_CONFIG, log_warn(LD_CONFIG,
"Empty socket path in hidden service port configuration."); "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 if (strchr(addrport, ':') || strchr(addrport, '.')) {
/* else try it as an IP:port pair if it has a : or . in it */ /* else try it as an IP:port pair if it has a : or . in it */
if (tor_addr_port_lookup(addrport, &addr, &p)<0) { if (tor_addr_port_lookup(addrport, &addr, &p)<0) {