Loading changes/bug12585 0 → 100644 +9 −0 Original line number Diff line number Diff line o Major features (security) - Implementation of SocksSocket option - SocksSocket implements 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. doc/tor.1.txt +10 −1 Original line number Diff line number Diff line Loading @@ -294,7 +294,7 @@ GENERAL OPTIONS [[ControlSocket]] **ControlSocket** __Path__:: Like ControlPort, but listens on a Unix domain socket, rather than a TCP socket. (Unix and Unix-like systems only.) socket. '0' disables ControlSocket (Unix and Unix-like systems only.) [[ControlSocketsGroupWritable]] **ControlSocketsGroupWritable** **0**|**1**:: If this option is set to 0, don't allow the filesystem group to read and Loading Loading @@ -483,6 +483,15 @@ GENERAL OPTIONS in accordance to RFC 1929. Both username and password must be between 1 and 255 characters. [[SocksSocket]] **SocksSocket** __Path__:: 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 the SocksSocket socket readable and writable by the default GID. (Default: 0) [[KeepalivePeriod]] **KeepalivePeriod** __NUM__:: To keep firewalls from expiring connections, send a padding keepalive cell every NUM seconds on open connections that are in use. If the connection Loading src/common/address.c +18 −0 Original line number Diff line number Diff line Loading @@ -121,6 +121,15 @@ tor_addr_to_sockaddr(const tor_addr_t *a, } } /** Set address <b>a</b> to zero. This address belongs to * the AF_UNIX family. */ static void tor_addr_make_af_unix(tor_addr_t *a) { memset(a, 0, sizeof(*a)); a->family = AF_UNIX; } /** Set the tor_addr_t in <b>a</b> to contain the socket address contained in * <b>sa</b>. */ int Loading @@ -142,6 +151,9 @@ tor_addr_from_sockaddr(tor_addr_t *a, const struct sockaddr *sa, tor_addr_from_in6(a, &sin6->sin6_addr); if (port_out) *port_out = ntohs(sin6->sin6_port); } else if (sa->sa_family == AF_UNIX) { tor_addr_make_af_unix(a); return 0; } else { tor_addr_make_unspec(a); return -1; Loading Loading @@ -421,6 +433,10 @@ tor_addr_to_str(char *dest, const tor_addr_t *addr, size_t len, int decorate) ptr = dest; } break; case AF_UNIX: tor_snprintf(dest, len, "AF_UNIX"); ptr = dest; break; default: return NULL; } Loading Loading @@ -816,6 +832,8 @@ tor_addr_is_null(const tor_addr_t *addr) } case AF_INET: return (tor_addr_to_ipv4n(addr) == 0); case AF_UNIX: return 1; case AF_UNSPEC: return 1; default: Loading src/or/config.c +100 −10 Original line number Diff line number Diff line Loading @@ -200,6 +200,8 @@ 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"), V(CookieAuthFile, STRING, NULL), Loading Loading @@ -1047,6 +1049,20 @@ 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. */ Loading Loading @@ -6034,22 +6050,87 @@ parse_port_config(smartlist_t *out, /** Parse a list of config_line_t for an AF_UNIX unix socket listener option * from <b>cfg</b> and add them to <b>out</b>. No fancy options are * supported: the line contains nothing but the path to the AF_UNIX socket. */ * supported: the line contains nothing but the path to the AF_UNIX socket. * We support a *Socket 0 syntax to explicitly disable if we enable by * default. To use this, pass a non-NULL list containing the default * paths into this function as the 2nd parameter, and if no config lines at all * are present they will be added to the output list. If the only config line * present is '0' the input list will be unmodified. */ static int parse_unix_socket_config(smartlist_t *out, const config_line_t *cfg, int listener_type) parse_unix_socket_config(smartlist_t *out, smartlist_t *defaults, const config_line_t *cfg, int listener_type) { /* We can say things like SocksSocket 0 or ControlSocket 0 to explicitly * disable this feature; use this to track if we've seen a disable line */ int unix_socket_disable = 0; size_t len; smartlist_t *ports_to_add = NULL; if (!out) return 0; ports_to_add = smartlist_new(); for ( ; cfg; cfg = cfg->next) { size_t len = strlen(cfg->value); if (strcmp(cfg->value, "0") != 0) { /* We have a non-disable; add it */ len = strlen(cfg->value); port_cfg_t *port = tor_malloc_zero(sizeof(port_cfg_t) + len + 1); port->is_unix_addr = 1; memcpy(port->unix_addr, cfg->value, len+1); port->type = listener_type; if (listener_type == CONN_TYPE_AP_LISTENER) { /* Some more bits to twiddle for this case * * XXX this should support parsing the same options * parse_port_config() does, and probably that code should be * factored out into a function we can call from here. For * now, some reasonable defaults. */ port->ipv4_traffic = 1; port->ipv6_traffic = 1; port->cache_ipv4_answers = 1; port->cache_ipv6_answers = 1; } smartlist_add(ports_to_add, port); } else { /* Keep track that we've seen a disable */ unix_socket_disable = 1; } } if (unix_socket_disable) { if (smartlist_len(ports_to_add) > 0) { /* We saw a disable line and a path; bad news */ SMARTLIST_FOREACH(ports_to_add, port_cfg_t *, port, tor_free(port)); smartlist_free(ports_to_add); return -1; } /* else we have a disable and nothing else, so add nothing to out */ } else { /* No disable; do we have any ports to add that we parsed? */ if (smartlist_len(ports_to_add) > 0) { SMARTLIST_FOREACH_BEGIN(ports_to_add, port_cfg_t *, port) { smartlist_add(out, port); } SMARTLIST_FOREACH_END(port); } else if (defaults != NULL && smartlist_len(defaults) > 0) { /* No, but we have some defaults to copy */ SMARTLIST_FOREACH_BEGIN(defaults, const port_cfg_t *, defport) { tor_assert(defport->is_unix_addr); tor_assert(defport->unix_addr); len = sizeof(port_cfg_t) + strlen(defport->unix_addr) + 1; port_cfg_t *port = tor_malloc_zero(len); memcpy(port, defport, len); smartlist_add(out, port); } SMARTLIST_FOREACH_END(defport); } /* Free the temporary smartlist we used */ smartlist_free(ports_to_add); } return 0; Loading Loading @@ -6143,12 +6224,19 @@ parse_ports(or_options_t *options, int validate_only, "configuration"); goto err; } if (parse_unix_socket_config(ports, if (parse_unix_socket_config(ports, NULL, options->ControlSocket, CONN_TYPE_CONTROL_LISTENER) < 0) { *msg = tor_strdup("Invalid ControlSocket configuration"); goto err; } if (parse_unix_socket_config(ports, NULL, options->SocksSocket, CONN_TYPE_AP_LISTENER) < 0) { *msg = tor_strdup("Invalid SocksSocket configuration"); goto err; } } if (! options->ClientOnly) { if (parse_port_config(ports, Loading Loading @@ -6192,6 +6280,8 @@ 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 = Loading src/or/connection.c +117 −29 Original line number Diff line number Diff line Loading @@ -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; } Loading Loading @@ -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, Loading Loading @@ -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 " Loading @@ -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); Loading Loading @@ -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); Loading @@ -1040,8 +1092,8 @@ 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", tor_socket_strerror(tor_socket_errno(-1))); Loading Loading @@ -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))); Loading @@ -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) 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); Loading @@ -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); Loading @@ -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) { Loading @@ -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.", Loading Loading @@ -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; } Loading Loading @@ -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) { Loading Loading @@ -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; } Loading @@ -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."); Loading Loading @@ -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 Loading Loading
changes/bug12585 0 → 100644 +9 −0 Original line number Diff line number Diff line o Major features (security) - Implementation of SocksSocket option - SocksSocket implements 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.
doc/tor.1.txt +10 −1 Original line number Diff line number Diff line Loading @@ -294,7 +294,7 @@ GENERAL OPTIONS [[ControlSocket]] **ControlSocket** __Path__:: Like ControlPort, but listens on a Unix domain socket, rather than a TCP socket. (Unix and Unix-like systems only.) socket. '0' disables ControlSocket (Unix and Unix-like systems only.) [[ControlSocketsGroupWritable]] **ControlSocketsGroupWritable** **0**|**1**:: If this option is set to 0, don't allow the filesystem group to read and Loading Loading @@ -483,6 +483,15 @@ GENERAL OPTIONS in accordance to RFC 1929. Both username and password must be between 1 and 255 characters. [[SocksSocket]] **SocksSocket** __Path__:: 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 the SocksSocket socket readable and writable by the default GID. (Default: 0) [[KeepalivePeriod]] **KeepalivePeriod** __NUM__:: To keep firewalls from expiring connections, send a padding keepalive cell every NUM seconds on open connections that are in use. If the connection Loading
src/common/address.c +18 −0 Original line number Diff line number Diff line Loading @@ -121,6 +121,15 @@ tor_addr_to_sockaddr(const tor_addr_t *a, } } /** Set address <b>a</b> to zero. This address belongs to * the AF_UNIX family. */ static void tor_addr_make_af_unix(tor_addr_t *a) { memset(a, 0, sizeof(*a)); a->family = AF_UNIX; } /** Set the tor_addr_t in <b>a</b> to contain the socket address contained in * <b>sa</b>. */ int Loading @@ -142,6 +151,9 @@ tor_addr_from_sockaddr(tor_addr_t *a, const struct sockaddr *sa, tor_addr_from_in6(a, &sin6->sin6_addr); if (port_out) *port_out = ntohs(sin6->sin6_port); } else if (sa->sa_family == AF_UNIX) { tor_addr_make_af_unix(a); return 0; } else { tor_addr_make_unspec(a); return -1; Loading Loading @@ -421,6 +433,10 @@ tor_addr_to_str(char *dest, const tor_addr_t *addr, size_t len, int decorate) ptr = dest; } break; case AF_UNIX: tor_snprintf(dest, len, "AF_UNIX"); ptr = dest; break; default: return NULL; } Loading Loading @@ -816,6 +832,8 @@ tor_addr_is_null(const tor_addr_t *addr) } case AF_INET: return (tor_addr_to_ipv4n(addr) == 0); case AF_UNIX: return 1; case AF_UNSPEC: return 1; default: Loading
src/or/config.c +100 −10 Original line number Diff line number Diff line Loading @@ -200,6 +200,8 @@ 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"), V(CookieAuthFile, STRING, NULL), Loading Loading @@ -1047,6 +1049,20 @@ 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. */ Loading Loading @@ -6034,22 +6050,87 @@ parse_port_config(smartlist_t *out, /** Parse a list of config_line_t for an AF_UNIX unix socket listener option * from <b>cfg</b> and add them to <b>out</b>. No fancy options are * supported: the line contains nothing but the path to the AF_UNIX socket. */ * supported: the line contains nothing but the path to the AF_UNIX socket. * We support a *Socket 0 syntax to explicitly disable if we enable by * default. To use this, pass a non-NULL list containing the default * paths into this function as the 2nd parameter, and if no config lines at all * are present they will be added to the output list. If the only config line * present is '0' the input list will be unmodified. */ static int parse_unix_socket_config(smartlist_t *out, const config_line_t *cfg, int listener_type) parse_unix_socket_config(smartlist_t *out, smartlist_t *defaults, const config_line_t *cfg, int listener_type) { /* We can say things like SocksSocket 0 or ControlSocket 0 to explicitly * disable this feature; use this to track if we've seen a disable line */ int unix_socket_disable = 0; size_t len; smartlist_t *ports_to_add = NULL; if (!out) return 0; ports_to_add = smartlist_new(); for ( ; cfg; cfg = cfg->next) { size_t len = strlen(cfg->value); if (strcmp(cfg->value, "0") != 0) { /* We have a non-disable; add it */ len = strlen(cfg->value); port_cfg_t *port = tor_malloc_zero(sizeof(port_cfg_t) + len + 1); port->is_unix_addr = 1; memcpy(port->unix_addr, cfg->value, len+1); port->type = listener_type; if (listener_type == CONN_TYPE_AP_LISTENER) { /* Some more bits to twiddle for this case * * XXX this should support parsing the same options * parse_port_config() does, and probably that code should be * factored out into a function we can call from here. For * now, some reasonable defaults. */ port->ipv4_traffic = 1; port->ipv6_traffic = 1; port->cache_ipv4_answers = 1; port->cache_ipv6_answers = 1; } smartlist_add(ports_to_add, port); } else { /* Keep track that we've seen a disable */ unix_socket_disable = 1; } } if (unix_socket_disable) { if (smartlist_len(ports_to_add) > 0) { /* We saw a disable line and a path; bad news */ SMARTLIST_FOREACH(ports_to_add, port_cfg_t *, port, tor_free(port)); smartlist_free(ports_to_add); return -1; } /* else we have a disable and nothing else, so add nothing to out */ } else { /* No disable; do we have any ports to add that we parsed? */ if (smartlist_len(ports_to_add) > 0) { SMARTLIST_FOREACH_BEGIN(ports_to_add, port_cfg_t *, port) { smartlist_add(out, port); } SMARTLIST_FOREACH_END(port); } else if (defaults != NULL && smartlist_len(defaults) > 0) { /* No, but we have some defaults to copy */ SMARTLIST_FOREACH_BEGIN(defaults, const port_cfg_t *, defport) { tor_assert(defport->is_unix_addr); tor_assert(defport->unix_addr); len = sizeof(port_cfg_t) + strlen(defport->unix_addr) + 1; port_cfg_t *port = tor_malloc_zero(len); memcpy(port, defport, len); smartlist_add(out, port); } SMARTLIST_FOREACH_END(defport); } /* Free the temporary smartlist we used */ smartlist_free(ports_to_add); } return 0; Loading Loading @@ -6143,12 +6224,19 @@ parse_ports(or_options_t *options, int validate_only, "configuration"); goto err; } if (parse_unix_socket_config(ports, if (parse_unix_socket_config(ports, NULL, options->ControlSocket, CONN_TYPE_CONTROL_LISTENER) < 0) { *msg = tor_strdup("Invalid ControlSocket configuration"); goto err; } if (parse_unix_socket_config(ports, NULL, options->SocksSocket, CONN_TYPE_AP_LISTENER) < 0) { *msg = tor_strdup("Invalid SocksSocket configuration"); goto err; } } if (! options->ClientOnly) { if (parse_port_config(ports, Loading Loading @@ -6192,6 +6280,8 @@ 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 = Loading
src/or/connection.c +117 −29 Original line number Diff line number Diff line Loading @@ -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; } Loading Loading @@ -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, Loading Loading @@ -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 " Loading @@ -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); Loading Loading @@ -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); Loading @@ -1040,8 +1092,8 @@ 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", tor_socket_strerror(tor_socket_errno(-1))); Loading Loading @@ -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))); Loading @@ -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) 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); Loading @@ -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); Loading @@ -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) { Loading @@ -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.", Loading Loading @@ -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; } Loading Loading @@ -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) { Loading Loading @@ -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; } Loading @@ -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."); Loading Loading @@ -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 Loading