diff options
author | Jacob Appelbaum <jacob@appelbaum.net> | 2014-08-11 12:27:04 -0700 |
---|---|---|
committer | Andrea Shepard <andrea@torproject.org> | 2015-01-07 17:42:57 +0000 |
commit | 8d59ddf3cba541c6578dff121e8f0623a7606bab (patch) | |
tree | a85c724acac38346025042b128c60f20337dda05 /src/or/connection.c | |
parent | 1abd526c75eade83318a6ec6aff84d5f0f079a3b (diff) | |
download | tor-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.c | 246 |
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 |