|
@@ -308,6 +308,8 @@ entry_connection_new(int type, int socket_family)
|
|
|
entry_conn->ipv4_traffic_ok = 1;
|
|
|
else if (socket_family == AF_INET6)
|
|
|
entry_conn->ipv6_traffic_ok = 1;
|
|
|
+ else if (socket_family == AF_UNIX)
|
|
|
+ entry_conn->is_socks_socket = 1;
|
|
|
return entry_conn;
|
|
|
}
|
|
|
|
|
@@ -516,9 +518,10 @@ connection_free_(connection_t *conn)
|
|
|
buf_free(conn->outbuf);
|
|
|
} else {
|
|
|
if (conn->socket_family == AF_UNIX) {
|
|
|
- /* For now only control ports can be Unix domain sockets
|
|
|
+ /* 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);
|
|
|
+ tor_assert(conn->type == CONN_TYPE_CONTROL_LISTENER ||
|
|
|
+ conn->type == CONN_TYPE_AP_LISTENER);
|
|
|
|
|
|
if (unlink(conn->address) < 0 && errno != ENOENT) {
|
|
|
log_warn(LD_NET, "Could not unlink %s: %s", conn->address,
|
|
@@ -915,13 +918,57 @@ warn_too_many_conns(void)
|
|
|
}
|
|
|
|
|
|
#ifdef HAVE_SYS_UN_H
|
|
|
+
|
|
|
+#define UNIX_SOCKET_PURPOSE_CONTROL_SOCKET 0
|
|
|
+#define UNIX_SOCKET_PURPOSE_SOCKS_SOCKET 1
|
|
|
+
|
|
|
+/** Check if the purpose isn't one of the ones we know what to do with */
|
|
|
+
|
|
|
+static int
|
|
|
+is_valid_unix_socket_purpose(int purpose)
|
|
|
+{
|
|
|
+ int valid = 0;
|
|
|
+
|
|
|
+ switch (purpose) {
|
|
|
+ case UNIX_SOCKET_PURPOSE_CONTROL_SOCKET:
|
|
|
+ case UNIX_SOCKET_PURPOSE_SOCKS_SOCKET:
|
|
|
+ valid = 1;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ return valid;
|
|
|
+}
|
|
|
+
|
|
|
+/** Return a string description of a unix socket purpose */
|
|
|
+static const char *
|
|
|
+unix_socket_purpose_to_string(int purpose)
|
|
|
+{
|
|
|
+ const char *s = "unknown-purpose socket";
|
|
|
+
|
|
|
+ switch (purpose) {
|
|
|
+ case UNIX_SOCKET_PURPOSE_CONTROL_SOCKET:
|
|
|
+ s = "control socket";
|
|
|
+ break;
|
|
|
+ case UNIX_SOCKET_PURPOSE_SOCKS_SOCKET:
|
|
|
+ s = "SOCKS socket";
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ return s;
|
|
|
+}
|
|
|
+
|
|
|
/** 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(const or_options_t *options, const char *path)
|
|
|
+check_location_for_unix_socket(const or_options_t *options, const char *path,
|
|
|
+ int purpose)
|
|
|
{
|
|
|
int r = -1;
|
|
|
- char *p = tor_strdup(path);
|
|
|
+ char *p = NULL;
|
|
|
+
|
|
|
+ tor_assert(is_valid_unix_socket_purpose(purpose));
|
|
|
+
|
|
|
+ p = tor_strdup(path);
|
|
|
cpd_check_t flags = CPD_CHECK_MODE_ONLY;
|
|
|
if (get_parent_directory(p)<0 || p[0] != '/') {
|
|
|
log_warn(LD_GENERAL, "Bad unix socket address '%s'. Tor does not support "
|
|
@@ -929,18 +976,23 @@ check_location_for_unix_socket(const or_options_t *options, const char *path)
|
|
|
goto done;
|
|
|
}
|
|
|
|
|
|
- if (options->ControlSocketsGroupWritable)
|
|
|
+ if ((purpose == UNIX_SOCKET_PURPOSE_CONTROL_SOCKET &&
|
|
|
+ options->ControlSocketsGroupWritable) ||
|
|
|
+ (purpose == UNIX_SOCKET_PURPOSE_SOCKS_SOCKET &&
|
|
|
+ options->SocksSocketsGroupWritable)) {
|
|
|
flags |= CPD_GROUP_OK;
|
|
|
+ }
|
|
|
|
|
|
if (check_private_dir(p, flags, options->User) < 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 connect to it, so Tor is "
|
|
|
- "being careful.)", escpath, escdir,
|
|
|
+ log_warn(LD_GENERAL, "Before Tor can create a %s 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 connect to it, so Tor is being "
|
|
|
+ "careful.)",
|
|
|
+ unix_socket_purpose_to_string(purpose), escpath, escdir,
|
|
|
options->ControlSocketsGroupWritable ? " and group" : "");
|
|
|
tor_free(escpath);
|
|
|
tor_free(escdir);
|
|
@@ -1030,8 +1082,8 @@ connection_listener_new(const struct sockaddr *listensockaddr,
|
|
|
|
|
|
if (listensockaddr->sa_family == AF_INET ||
|
|
|
listensockaddr->sa_family == AF_INET6) {
|
|
|
- int is_tcp = (type != CONN_TYPE_AP_DNS_LISTENER);
|
|
|
- if (is_tcp)
|
|
|
+ int is_stream = (type != CONN_TYPE_AP_DNS_LISTENER);
|
|
|
+ if (is_stream)
|
|
|
start_reading = 1;
|
|
|
|
|
|
tor_addr_from_sockaddr(&addr, listensockaddr, &usePort);
|
|
@@ -1040,10 +1092,10 @@ connection_listener_new(const struct sockaddr *listensockaddr,
|
|
|
conn_type_to_string(type), fmt_addrport(&addr, usePort));
|
|
|
|
|
|
s = tor_open_socket_nonblocking(tor_addr_family(&addr),
|
|
|
- is_tcp ? SOCK_STREAM : SOCK_DGRAM,
|
|
|
- is_tcp ? IPPROTO_TCP: IPPROTO_UDP);
|
|
|
+ is_stream ? SOCK_STREAM : SOCK_DGRAM,
|
|
|
+ is_stream ? IPPROTO_TCP: IPPROTO_UDP);
|
|
|
if (!SOCKET_OK(s)) {
|
|
|
- log_warn(LD_NET,"Socket creation failed: %s",
|
|
|
+ log_warn(LD_NET, "Socket creation failed: %s",
|
|
|
tor_socket_strerror(tor_socket_errno(-1)));
|
|
|
goto err;
|
|
|
}
|
|
@@ -1100,7 +1152,7 @@ connection_listener_new(const struct sockaddr *listensockaddr,
|
|
|
goto err;
|
|
|
}
|
|
|
|
|
|
- if (is_tcp) {
|
|
|
+ if (is_stream) {
|
|
|
if (tor_listen(s) < 0) {
|
|
|
log_warn(LD_NET, "Could not listen on %s:%u: %s", address, usePort,
|
|
|
tor_socket_strerror(tor_socket_errno(s)));
|
|
@@ -1123,15 +1175,25 @@ connection_listener_new(const struct sockaddr *listensockaddr,
|
|
|
tor_addr_from_sockaddr(&addr2, (struct sockaddr*)&ss, &gotPort);
|
|
|
}
|
|
|
#ifdef HAVE_SYS_UN_H
|
|
|
+ /*
|
|
|
+ * AF_UNIX generic setup stuff (this covers both CONN_TYPE_CONTROL_LISTENER
|
|
|
+ * and CONN_TYPE_AP_LISTENER cases)
|
|
|
+ */
|
|
|
} 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 can be Unix domain sockets
|
|
|
+ /* 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);
|
|
|
+ tor_assert(type == CONN_TYPE_CONTROL_LISTENER ||
|
|
|
+ type == CONN_TYPE_AP_LISTENER);
|
|
|
|
|
|
- if (check_location_for_unix_socket(options, address) < 0)
|
|
|
- goto err;
|
|
|
+ if (check_location_for_unix_socket(options, address,
|
|
|
+ (type == CONN_TYPE_CONTROL_LISTENER) ?
|
|
|
+ UNIX_SOCKET_PURPOSE_CONTROL_SOCKET :
|
|
|
+ UNIX_SOCKET_PURPOSE_SOCKS_SOCKET) < 0) {
|
|
|
+ goto err;
|
|
|
+ }
|
|
|
|
|
|
log_notice(LD_NET, "Opening %s on %s",
|
|
|
conn_type_to_string(type), address);
|
|
@@ -1143,17 +1205,20 @@ connection_listener_new(const struct sockaddr *listensockaddr,
|
|
|
strerror(errno));
|
|
|
goto err;
|
|
|
}
|
|
|
+
|
|
|
s = tor_open_socket_nonblocking(AF_UNIX, SOCK_STREAM, 0);
|
|
|
if (! SOCKET_OK(s)) {
|
|
|
log_warn(LD_NET,"Socket creation failed: %s.", strerror(errno));
|
|
|
goto err;
|
|
|
}
|
|
|
|
|
|
- if (bind(s, listensockaddr, (socklen_t)sizeof(struct sockaddr_un)) == -1) {
|
|
|
+ if (bind(s, listensockaddr,
|
|
|
+ (socklen_t)sizeof(struct sockaddr_un)) == -1) {
|
|
|
log_warn(LD_NET,"Bind to %s failed: %s.", address,
|
|
|
tor_socket_strerror(tor_socket_errno(s)));
|
|
|
goto err;
|
|
|
}
|
|
|
+
|
|
|
#ifdef HAVE_PWD_H
|
|
|
if (options->User) {
|
|
|
pw = tor_getpwnam(options->User);
|
|
@@ -1168,13 +1233,27 @@ connection_listener_new(const struct sockaddr *listensockaddr,
|
|
|
}
|
|
|
}
|
|
|
#endif
|
|
|
- if (options->ControlSocketsGroupWritable) {
|
|
|
+
|
|
|
+ if ((type == CONN_TYPE_CONTROL_LISTENER &&
|
|
|
+ options->ControlSocketsGroupWritable) ||
|
|
|
+ (type == CONN_TYPE_AP_LISTENER &&
|
|
|
+ options->SocksSocketsGroupWritable)) {
|
|
|
/* 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);
|
|
|
goto err;
|
|
|
}
|
|
|
+ } else if ((type == CONN_TYPE_CONTROL_LISTENER &&
|
|
|
+ !(options->ControlSocketsGroupWritable)) ||
|
|
|
+ (type == CONN_TYPE_AP_LISTENER &&
|
|
|
+ !(options->SocksSocketsGroupWritable))) {
|
|
|
+ /* We need to use chmod; fchmod doesn't work on sockets on all
|
|
|
+ * platforms. */
|
|
|
+ if (chmod(address, 0600) < 0) {
|
|
|
+ log_warn(LD_FS,"Unable to make %s group-writable.", address);
|
|
|
+ goto err;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
if (listen(s, SOMAXCONN) < 0) {
|
|
@@ -1182,8 +1261,6 @@ connection_listener_new(const struct sockaddr *listensockaddr,
|
|
|
tor_socket_strerror(tor_socket_errno(s)));
|
|
|
goto err;
|
|
|
}
|
|
|
-#else
|
|
|
- (void)options;
|
|
|
#endif /* HAVE_SYS_UN_H */
|
|
|
} else {
|
|
|
log_err(LD_BUG, "Got unexpected address family %d.",
|
|
@@ -1294,6 +1371,8 @@ check_sockaddr(const struct sockaddr *sa, int len, int level)
|
|
|
"Address for new connection has address/port equal to zero.");
|
|
|
ok = 0;
|
|
|
}
|
|
|
+ } else if (sa->sa_family == AF_UNIX) {
|
|
|
+ ok = 1;
|
|
|
} else {
|
|
|
ok = 0;
|
|
|
}
|
|
@@ -1378,7 +1457,8 @@ connection_handle_listener_read(connection_t *conn, int new_type)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
- if (conn->socket_family == AF_INET || conn->socket_family == AF_INET6) {
|
|
|
+ if (conn->socket_family == AF_INET || conn->socket_family == AF_INET6 ||
|
|
|
+ (conn->socket_family == AF_UNIX && new_type == CONN_TYPE_AP)) {
|
|
|
tor_addr_t addr;
|
|
|
uint16_t port;
|
|
|
if (check_sockaddr(remote, remotelen, LOG_INFO)<0) {
|
|
@@ -1419,7 +1499,16 @@ connection_handle_listener_read(connection_t *conn, int new_type)
|
|
|
newconn->port = port;
|
|
|
newconn->address = tor_dup_addr(&addr);
|
|
|
|
|
|
- if (new_type == CONN_TYPE_AP) {
|
|
|
+ if (new_type == CONN_TYPE_AP && conn->socket_family != AF_UNIX) {
|
|
|
+ log_notice(LD_NET, "New SOCKS connection opened from %s.",
|
|
|
+ fmt_and_decorate_addr(&addr));
|
|
|
+ TO_ENTRY_CONN(newconn)->socks_request->socks_prefer_no_auth =
|
|
|
+ TO_LISTENER_CONN(conn)->socks_prefer_no_auth;
|
|
|
+ }
|
|
|
+ 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");
|
|
|
TO_ENTRY_CONN(newconn)->socks_request->socks_prefer_no_auth =
|
|
|
TO_LISTENER_CONN(conn)->socks_prefer_no_auth;
|
|
|
}
|
|
@@ -1428,9 +1517,7 @@ connection_handle_listener_read(connection_t *conn, int new_type)
|
|
|
fmt_and_decorate_addr(&addr));
|
|
|
}
|
|
|
|
|
|
- } else if (conn->socket_family == AF_UNIX) {
|
|
|
- /* For now only control ports can be Unix domain sockets
|
|
|
- * and listeners at the same time */
|
|
|
+ } else if (conn->socket_family == AF_UNIX && conn->type != CONN_TYPE_AP) {
|
|
|
tor_assert(conn->type == CONN_TYPE_CONTROL_LISTENER);
|
|
|
tor_assert(new_type == CONN_TYPE_CONTROL);
|
|
|
log_notice(LD_CONTROL, "New control connection opened.");
|
|
@@ -2392,6 +2479,7 @@ connection_is_rate_limited(connection_t *conn)
|
|
|
return 0; /* Internal connection */
|
|
|
else if (! options->CountPrivateBandwidth &&
|
|
|
(tor_addr_family(&conn->addr) == AF_UNSPEC || /* no address */
|
|
|
+ tor_addr_family(&conn->addr) == AF_UNIX || /* no address */
|
|
|
tor_addr_is_internal(&conn->addr, 0)))
|
|
|
return 0; /* Internal address */
|
|
|
else
|