summaryrefslogtreecommitdiff
path: root/src/or/connection.c
diff options
context:
space:
mode:
authorJacob Appelbaum <jacob@appelbaum.net>2014-08-11 12:27:04 -0700
committerAndrea Shepard <andrea@torproject.org>2015-01-07 17:42:57 +0000
commit8d59ddf3cba541c6578dff121e8f0623a7606bab (patch)
treea85c724acac38346025042b128c60f20337dda05 /src/or/connection.c
parent1abd526c75eade83318a6ec6aff84d5f0f079a3b (diff)
downloadtor-8d59ddf3cba541c6578dff121e8f0623a7606bab.tar.gz
tor-8d59ddf3cba541c6578dff121e8f0623a7606bab.zip
Commit second draft of Jake's SOCKS5-over-AF_UNIX patch. See ticket #12585.
Signed-off-by: Andrea Shepard <andrea@torproject.org>
Diffstat (limited to 'src/or/connection.c')
-rw-r--r--src/or/connection.c246
1 files changed, 195 insertions, 51 deletions
diff --git a/src/or/connection.c b/src/or/connection.c
index c67cc3c111..ad7e6de9b6 100644
--- a/src/or/connection.c
+++ b/src/or/connection.c
@@ -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,
@@ -954,6 +957,47 @@ check_location_for_unix_socket(const or_options_t *options, const char *path)
}
#endif
+#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_socks_unix_socket(const 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 || p[0] != '/') {
+ log_warn(LD_GENERAL, "Bad unix socket address '%s'. Tor does not support "
+ "relative paths for unix sockets.", path);
+ goto done;
+ }
+
+ if (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 SocksSocket 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,
+ options->SocksSocketsGroupWritable ? " and group" : "");
+ tor_free(escpath);
+ tor_free(escdir);
+ goto done;
+ }
+
+ r = 0;
+ done:
+ tor_free(p);
+ return r;
+}
+#endif
+
/** Tell the TCP stack that it shouldn't wait for a long time after
* <b>sock</b> has closed before reusing its port. Return 0 on success,
* -1 on failure. */
@@ -1029,30 +1073,103 @@ connection_listener_new(const struct sockaddr *listensockaddr,
}
if (listensockaddr->sa_family == AF_INET ||
- listensockaddr->sa_family == AF_INET6) {
+ listensockaddr->sa_family == AF_INET6 ||
+ (listensockaddr->sa_family == AF_UNIX &&
+ type != CONN_TYPE_CONTROL_LISTENER)) {
int is_tcp = (type != CONN_TYPE_AP_DNS_LISTENER);
if (is_tcp)
start_reading = 1;
- tor_addr_from_sockaddr(&addr, listensockaddr, &usePort);
+ if ( listensockaddr->sa_family == AF_INET ||
+ listensockaddr->sa_family == AF_INET6) {
- log_notice(LD_NET, "Opening %s on %s",
- 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);
- if (!SOCKET_OK(s)) {
- log_warn(LD_NET,"Socket creation failed: %s",
- tor_socket_strerror(tor_socket_errno(-1)));
- goto err;
+ tor_addr_from_sockaddr(&addr, listensockaddr, &usePort);
+
+ log_notice(LD_NET, "Opening %s on %s",
+ 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);
+ if (!SOCKET_OK(s)) {
+ log_warn(LD_NET, "Socket creation failed: %s",
+ tor_socket_strerror(tor_socket_errno(-1)));
+ goto err;
+ }
+
+ if (make_socket_reuseable(s) < 0) {
+ log_warn(LD_NET, "Error setting SO_REUSEADDR flag on %s: %s",
+ conn_type_to_string(type),
+ tor_socket_strerror(errno));
+ }
}
- if (make_socket_reuseable(s) < 0) {
- log_warn(LD_NET, "Error setting SO_REUSEADDR flag on %s: %s",
- conn_type_to_string(type),
- tor_socket_strerror(errno));
+#ifdef HAVE_SYS_UN_H
+ if (listensockaddr->sa_family == AF_UNIX &&
+ type != CONN_TYPE_CONTROL_LISTENER) {
+ tor_assert(listensockaddr->sa_family == AF_UNIX);
+
+ if (check_location_for_socks_unix_socket(options, address) < 0)
+ goto err;
+
+ log_notice(LD_NET, "Opening SocksSocket %s on %s",
+ conn_type_to_string(type), address);
+
+ tor_addr_make_unspec(&addr);
+
+ if (unlink(address) < 0 && errno != ENOENT) {
+ log_warn(LD_NET, "Could not unlink %s: %s", address,
+ strerror(errno));
+ goto err;
+ }
+
+ s = tor_open_socket_nonblocking(AF_UNIX, SOCK_STREAM, 0);
+ if (! SOCKET_OK(s)) {
+ log_warn(LD_NET, "SocksSocket socket creation failed: %s.",
+ strerror(errno));
+ goto err;
+ }
+
+ 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 = getpwnam(options->User);
+ if (pw == NULL) {
+ log_warn(LD_NET,
+ "Unable to chown() %s socket: user %s not found.",
+ address, options->User);
+ goto err;
+ } else if (chown(address, pw->pw_uid, pw->pw_gid) < 0) {
+ log_warn(LD_NET, "Unable to chown() %s socket: %s.",
+ address, strerror(errno));
+ goto err;
+ }
+ }
+#endif
+
+ if (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;
+ }
+ }
+
+ if (listen(s, SOMAXCONN) < 0) {
+ log_warn(LD_NET, "Could not listen on %s: %s", address,
+ tor_socket_strerror(tor_socket_errno(s)));
+ goto err;
+ }
}
+#else
+ (void)options;
+#endif /* HAVE_SYS_UN_H */
#if defined USE_TRANSPARENT && defined(IP_TRANSPARENT)
if (options->TransProxyType_parsed == TPT_TPROXY &&
@@ -1090,48 +1207,53 @@ connection_listener_new(const struct sockaddr *listensockaddr,
}
#endif
- if (bind(s,listensockaddr,socklen) < 0) {
- const char *helpfulhint = "";
- int e = tor_socket_errno(s);
- if (ERRNO_IS_EADDRINUSE(e))
- helpfulhint = ". Is Tor already running?";
- log_warn(LD_NET, "Could not bind to %s:%u: %s%s", address, usePort,
- tor_socket_strerror(e), helpfulhint);
- goto err;
- }
-
- if (is_tcp) {
- 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)));
+ if (listensockaddr->sa_family != AF_UNIX) {
+ if (bind(s,listensockaddr,socklen) < 0) {
+ const char *helpfulhint = "";
+ int e = tor_socket_errno(s);
+ if (ERRNO_IS_EADDRINUSE(e))
+ helpfulhint = ". Is Tor already running?";
+ log_warn(LD_NET, "Could not bind to %s:%u: %s%s", address, usePort,
+ tor_socket_strerror(e), helpfulhint);
goto err;
}
- }
- if (usePort != 0) {
- gotPort = usePort;
- } else {
- tor_addr_t addr2;
- struct sockaddr_storage ss;
- socklen_t ss_len=sizeof(ss);
- if (getsockname(s, (struct sockaddr*)&ss, &ss_len)<0) {
- log_warn(LD_NET, "getsockname() couldn't learn address for %s: %s",
- conn_type_to_string(type),
- tor_socket_strerror(tor_socket_errno(s)));
- gotPort = 0;
+ if (is_tcp) {
+ 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)));
+ goto err;
+ }
+ }
+
+ if (usePort != 0) {
+ gotPort = usePort;
+ } else {
+ tor_addr_t addr2;
+ struct sockaddr_storage ss;
+ socklen_t ss_len=sizeof(ss);
+ if (getsockname(s, (struct sockaddr*)&ss, &ss_len)<0) {
+ log_warn(LD_NET, "getsockname() couldn't learn address for %s: %s",
+ conn_type_to_string(type),
+ tor_socket_strerror(tor_socket_errno(s)));
+ gotPort = 0;
+ }
+ tor_addr_from_sockaddr(&addr2, (struct sockaddr*)&ss, &gotPort);
}
- tor_addr_from_sockaddr(&addr2, (struct sockaddr*)&ss, &gotPort);
}
#ifdef HAVE_SYS_UN_H
- } else if (listensockaddr->sa_family == AF_UNIX) {
+ } else if (listensockaddr->sa_family == AF_UNIX &&
+ type != CONN_TYPE_AP_LISTENER) {
start_reading = 1;
/* For now only control ports can be Unix domain sockets
* and listeners at the same time */
tor_assert(type == CONN_TYPE_CONTROL_LISTENER);
- if (check_location_for_unix_socket(options, address) < 0)
- goto err;
+ if ( type == CONN_TYPE_CONTROL_LISTENER ) {
+ if (check_location_for_unix_socket(options, address) < 0)
+ goto err;
+ }
log_notice(LD_NET, "Opening %s on %s",
conn_type_to_string(type), address);
@@ -1177,6 +1299,15 @@ connection_listener_new(const struct sockaddr *listensockaddr,
}
}
+ if (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;
+ }
+ }
+
if (listen(s, SOMAXCONN) < 0) {
log_warn(LD_NET, "Could not listen on %s: %s", address,
tor_socket_strerror(tor_socket_errno(s)));
@@ -1294,6 +1425,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 +1511,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 +1553,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_notice(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,7 +1571,7 @@ connection_handle_listener_read(connection_t *conn, int new_type)
fmt_and_decorate_addr(&addr));
}
- } else if (conn->socket_family == AF_UNIX) {
+ } else if (conn->socket_family == AF_UNIX && conn->type != CONN_TYPE_AP) {
/* For now only control ports can be Unix domain sockets
* and listeners at the same time */
tor_assert(conn->type == CONN_TYPE_CONTROL_LISTENER);
@@ -2392,6 +2535,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