mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-24 20:33:31 +01:00
Support connection_exit_connect() to AF_UNIX sockets
This commit is contained in:
parent
6564291601
commit
ca5ba2956b
@ -56,6 +56,11 @@
|
|||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_SYS_UN_H
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
static connection_t *connection_listener_new(
|
static connection_t *connection_listener_new(
|
||||||
const struct sockaddr *listensockaddr,
|
const struct sockaddr *listensockaddr,
|
||||||
socklen_t listensocklen, int type,
|
socklen_t listensocklen, int type,
|
||||||
@ -1585,6 +1590,98 @@ connection_init_accepted_conn(connection_t *conn,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
connection_connect_sockaddr(connection_t *conn,
|
||||||
|
const struct sockaddr *sa,
|
||||||
|
socklen_t sa_len,
|
||||||
|
const struct sockaddr *bindaddr,
|
||||||
|
socklen_t bindaddr_len,
|
||||||
|
int *socket_error)
|
||||||
|
{
|
||||||
|
tor_socket_t s;
|
||||||
|
int inprogress = 0;
|
||||||
|
const or_options_t *options = get_options();
|
||||||
|
int protocol_family;
|
||||||
|
|
||||||
|
tor_assert(conn);
|
||||||
|
tor_assert(sa);
|
||||||
|
tor_assert(socket_error);
|
||||||
|
|
||||||
|
if (get_n_open_sockets() >= get_options()->ConnLimit_-1) {
|
||||||
|
warn_too_many_conns();
|
||||||
|
*socket_error = SOCK_ERRNO(ENOBUFS);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
protocol_family = sa->sa_family;
|
||||||
|
|
||||||
|
if (get_options()->DisableNetwork) {
|
||||||
|
/* We should never even try to connect anyplace if DisableNetwork is set.
|
||||||
|
* Warn if we do, and refuse to make the connection. */
|
||||||
|
static ratelim_t disablenet_violated = RATELIM_INIT(30*60);
|
||||||
|
*socket_error = SOCK_ERRNO(ENETUNREACH);
|
||||||
|
log_fn_ratelim(&disablenet_violated, LOG_WARN, LD_BUG,
|
||||||
|
"Tried to open a socket with DisableNetwork set.");
|
||||||
|
tor_fragile_assert();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
s = tor_open_socket_nonblocking(protocol_family, SOCK_STREAM, 0);
|
||||||
|
if (! SOCKET_OK(s)) {
|
||||||
|
*socket_error = tor_socket_errno(-1);
|
||||||
|
log_warn(LD_NET,"Error creating network socket: %s",
|
||||||
|
tor_socket_strerror(*socket_error));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (make_socket_reuseable(s) < 0) {
|
||||||
|
log_warn(LD_NET, "Error setting SO_REUSEADDR flag on new connection: %s",
|
||||||
|
tor_socket_strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bindaddr && bind(s, bindaddr, bindaddr_len) < 0) {
|
||||||
|
*socket_error = tor_socket_errno(s);
|
||||||
|
log_warn(LD_NET,"Error binding network socket: %s",
|
||||||
|
tor_socket_strerror(*socket_error));
|
||||||
|
tor_close_socket(s);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
tor_assert(options);
|
||||||
|
if (options->ConstrainedSockets)
|
||||||
|
set_constrained_socket_buffers(s, (int)options->ConstrainedSockSize);
|
||||||
|
|
||||||
|
if (connect(s, sa, sa_len) < 0) {
|
||||||
|
int e = tor_socket_errno(s);
|
||||||
|
if (!ERRNO_IS_CONN_EINPROGRESS(e)) {
|
||||||
|
/* yuck. kill it. */
|
||||||
|
*socket_error = e;
|
||||||
|
log_info(LD_NET,
|
||||||
|
"connect() to socket failed: %s",
|
||||||
|
tor_socket_strerror(e));
|
||||||
|
tor_close_socket(s);
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
inprogress = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* it succeeded. we're connected. */
|
||||||
|
log_fn(inprogress ? LOG_DEBUG : LOG_INFO, LD_NET,
|
||||||
|
"Connection to socket %s (sock "TOR_SOCKET_T_FORMAT").",
|
||||||
|
inprogress ? "in progress" : "established", s);
|
||||||
|
conn->s = s;
|
||||||
|
if (connection_add_connecting(conn) < 0) {
|
||||||
|
/* no space, forget it */
|
||||||
|
*socket_error = SOCK_ERRNO(ENOBUFS);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return inprogress ? 0 : 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/** Take conn, make a nonblocking socket; try to connect to
|
/** Take conn, make a nonblocking socket; try to connect to
|
||||||
* addr:port (they arrive in *host order*). If fail, return -1 and if
|
* addr:port (they arrive in *host order*). If fail, return -1 and if
|
||||||
* applicable put your best guess about errno into *<b>socket_error</b>.
|
* applicable put your best guess about errno into *<b>socket_error</b>.
|
||||||
@ -1598,49 +1695,19 @@ int
|
|||||||
connection_connect(connection_t *conn, const char *address,
|
connection_connect(connection_t *conn, const char *address,
|
||||||
const tor_addr_t *addr, uint16_t port, int *socket_error)
|
const tor_addr_t *addr, uint16_t port, int *socket_error)
|
||||||
{
|
{
|
||||||
tor_socket_t s;
|
|
||||||
int inprogress = 0;
|
|
||||||
struct sockaddr_storage addrbuf;
|
struct sockaddr_storage addrbuf;
|
||||||
|
struct sockaddr_storage bind_addr_ss;
|
||||||
|
struct sockaddr *bind_addr = NULL;
|
||||||
struct sockaddr *dest_addr;
|
struct sockaddr *dest_addr;
|
||||||
int dest_addr_len;
|
int dest_addr_len, bind_addr_len = 0;
|
||||||
const or_options_t *options = get_options();
|
const or_options_t *options = get_options();
|
||||||
int protocol_family;
|
int protocol_family;
|
||||||
|
|
||||||
if (get_n_open_sockets() >= get_options()->ConnLimit_-1) {
|
|
||||||
warn_too_many_conns();
|
|
||||||
*socket_error = SOCK_ERRNO(ENOBUFS);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tor_addr_family(addr) == AF_INET6)
|
if (tor_addr_family(addr) == AF_INET6)
|
||||||
protocol_family = PF_INET6;
|
protocol_family = PF_INET6;
|
||||||
else
|
else
|
||||||
protocol_family = PF_INET;
|
protocol_family = PF_INET;
|
||||||
|
|
||||||
if (get_options()->DisableNetwork) {
|
|
||||||
/* We should never even try to connect anyplace if DisableNetwork is set.
|
|
||||||
* Warn if we do, and refuse to make the connection. */
|
|
||||||
static ratelim_t disablenet_violated = RATELIM_INIT(30*60);
|
|
||||||
*socket_error = SOCK_ERRNO(ENETUNREACH);
|
|
||||||
log_fn_ratelim(&disablenet_violated, LOG_WARN, LD_BUG,
|
|
||||||
"Tried to open a socket with DisableNetwork set.");
|
|
||||||
tor_fragile_assert();
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
s = tor_open_socket_nonblocking(protocol_family,SOCK_STREAM,IPPROTO_TCP);
|
|
||||||
if (! SOCKET_OK(s)) {
|
|
||||||
*socket_error = tor_socket_errno(-1);
|
|
||||||
log_warn(LD_NET,"Error creating network socket: %s",
|
|
||||||
tor_socket_strerror(*socket_error));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (make_socket_reuseable(s) < 0) {
|
|
||||||
log_warn(LD_NET, "Error setting SO_REUSEADDR flag on new connection: %s",
|
|
||||||
tor_socket_strerror(errno));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!tor_addr_is_loopback(addr)) {
|
if (!tor_addr_is_loopback(addr)) {
|
||||||
const tor_addr_t *ext_addr = NULL;
|
const tor_addr_t *ext_addr = NULL;
|
||||||
if (protocol_family == AF_INET &&
|
if (protocol_family == AF_INET &&
|
||||||
@ -1650,33 +1717,21 @@ connection_connect(connection_t *conn, const char *address,
|
|||||||
!tor_addr_is_null(&options->OutboundBindAddressIPv6_))
|
!tor_addr_is_null(&options->OutboundBindAddressIPv6_))
|
||||||
ext_addr = &options->OutboundBindAddressIPv6_;
|
ext_addr = &options->OutboundBindAddressIPv6_;
|
||||||
if (ext_addr) {
|
if (ext_addr) {
|
||||||
struct sockaddr_storage ext_addr_sa;
|
|
||||||
socklen_t ext_addr_len = 0;
|
socklen_t ext_addr_len = 0;
|
||||||
memset(&ext_addr_sa, 0, sizeof(ext_addr_sa));
|
memset(&bind_addr_ss, 0, sizeof(bind_addr_ss));
|
||||||
ext_addr_len = tor_addr_to_sockaddr(ext_addr, 0,
|
bind_addr_len = tor_addr_to_sockaddr(ext_addr, 0,
|
||||||
(struct sockaddr *) &ext_addr_sa,
|
(struct sockaddr *) &bind_addr_ss,
|
||||||
sizeof(ext_addr_sa));
|
sizeof(bind_addr_ss));
|
||||||
if (ext_addr_len == 0) {
|
if (ext_addr_len == 0) {
|
||||||
log_warn(LD_NET,
|
log_warn(LD_NET,
|
||||||
"Error converting OutboundBindAddress %s into sockaddr. "
|
"Error converting OutboundBindAddress %s into sockaddr. "
|
||||||
"Ignoring.", fmt_and_decorate_addr(ext_addr));
|
"Ignoring.", fmt_and_decorate_addr(ext_addr));
|
||||||
} else {
|
} else {
|
||||||
if (bind(s, (struct sockaddr *) &ext_addr_sa, ext_addr_len) < 0) {
|
bind_addr = (struct sockaddr *)&bind_addr_ss;
|
||||||
*socket_error = tor_socket_errno(s);
|
|
||||||
log_warn(LD_NET,"Error binding network socket to %s: %s",
|
|
||||||
fmt_and_decorate_addr(ext_addr),
|
|
||||||
tor_socket_strerror(*socket_error));
|
|
||||||
tor_close_socket(s);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tor_assert(options);
|
|
||||||
if (options->ConstrainedSockets)
|
|
||||||
set_constrained_socket_buffers(s, (int)options->ConstrainedSockSize);
|
|
||||||
|
|
||||||
memset(&addrbuf,0,sizeof(addrbuf));
|
memset(&addrbuf,0,sizeof(addrbuf));
|
||||||
dest_addr = (struct sockaddr*) &addrbuf;
|
dest_addr = (struct sockaddr*) &addrbuf;
|
||||||
dest_addr_len = tor_addr_to_sockaddr(addr, port, dest_addr, sizeof(addrbuf));
|
dest_addr_len = tor_addr_to_sockaddr(addr, port, dest_addr, sizeof(addrbuf));
|
||||||
@ -1685,36 +1740,51 @@ connection_connect(connection_t *conn, const char *address,
|
|||||||
log_debug(LD_NET, "Connecting to %s:%u.",
|
log_debug(LD_NET, "Connecting to %s:%u.",
|
||||||
escaped_safe_str_client(address), port);
|
escaped_safe_str_client(address), port);
|
||||||
|
|
||||||
if (connect(s, dest_addr, (socklen_t)dest_addr_len) < 0) {
|
return connection_connect_sockaddr(conn, dest_addr, dest_addr_len,
|
||||||
int e = tor_socket_errno(s);
|
bind_addr, bind_addr_len, socket_error);
|
||||||
if (!ERRNO_IS_CONN_EINPROGRESS(e)) {
|
}
|
||||||
/* yuck. kill it. */
|
|
||||||
*socket_error = e;
|
|
||||||
log_info(LD_NET,
|
|
||||||
"connect() to %s:%u failed: %s",
|
|
||||||
escaped_safe_str_client(address),
|
|
||||||
port, tor_socket_strerror(e));
|
|
||||||
tor_close_socket(s);
|
|
||||||
return -1;
|
|
||||||
} else {
|
|
||||||
inprogress = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* it succeeded. we're connected. */
|
#ifdef HAVE_SYS_UN_H
|
||||||
log_fn(inprogress?LOG_DEBUG:LOG_INFO, LD_NET,
|
|
||||||
"Connection to %s:%u %s (sock "TOR_SOCKET_T_FORMAT").",
|
/** Take conn, make a nonblocking socket; try to connect to
|
||||||
escaped_safe_str_client(address),
|
* an AF_UNIX socket at socket_path. If fail, return -1 and if applicable
|
||||||
port, inprogress?"in progress":"established", s);
|
* put your best guess about errno into *<b>socket_error</b>. Else assign s
|
||||||
conn->s = s;
|
* to conn-\>s: if connected return 1, if EAGAIN return 0.
|
||||||
if (connection_add_connecting(conn) < 0) {
|
*
|
||||||
/* no space, forget it */
|
* On success, add conn to the list of polled connections.
|
||||||
*socket_error = SOCK_ERRNO(ENOBUFS);
|
*/
|
||||||
|
int
|
||||||
|
connection_connect_unix(connection_t *conn, const char *socket_path,
|
||||||
|
int *socket_error)
|
||||||
|
{
|
||||||
|
struct sockaddr_un dest_addr;
|
||||||
|
|
||||||
|
tor_assert(socket_path);
|
||||||
|
|
||||||
|
/* Check that we'll be able to fit it into dest_addr later */
|
||||||
|
if (strlen(socket_path) + 1 > sizeof(dest_addr.sun_path)) {
|
||||||
|
log_warn(LD_NET,
|
||||||
|
"Path %s is too long for an AF_UNIX socket\n",
|
||||||
|
escaped_safe_str_client(socket_path));
|
||||||
|
*socket_error = SOCK_ERRNO(ENAMETOOLONG);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return inprogress ? 0 : 1;
|
|
||||||
|
memset(&dest_addr, 0, sizeof(dest_addr));
|
||||||
|
dest_addr.sun_family = AF_UNIX;
|
||||||
|
strlcpy(dest_addr.sun_path, socket_path, sizeof(dest_addr.sun_path));
|
||||||
|
|
||||||
|
log_debug(LD_NET,
|
||||||
|
"Connecting to AF_UNIX socket at %s.",
|
||||||
|
escaped_safe_str_client(socket_path));
|
||||||
|
|
||||||
|
return connection_connect_sockaddr(conn,
|
||||||
|
(struct sockaddr *)&dest_addr, sizeof(dest_addr),
|
||||||
|
NULL, 0, socket_error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif /* defined(HAVE_SYS_UN_H) */
|
||||||
|
|
||||||
/** Convert state number to string representation for logging purposes.
|
/** Convert state number to string representation for logging purposes.
|
||||||
*/
|
*/
|
||||||
static const char *
|
static const char *
|
||||||
|
@ -89,6 +89,13 @@ int connection_connect(connection_t *conn, const char *address,
|
|||||||
const tor_addr_t *addr,
|
const tor_addr_t *addr,
|
||||||
uint16_t port, int *socket_error);
|
uint16_t port, int *socket_error);
|
||||||
|
|
||||||
|
#ifdef HAVE_SYS_UN_H
|
||||||
|
|
||||||
|
int connection_connect_unix(connection_t *conn, const char *socket_path,
|
||||||
|
int *socket_error);
|
||||||
|
|
||||||
|
#endif /* defined(HAVE_SYS_UN_H) */
|
||||||
|
|
||||||
/** Maximum size of information that we can fit into SOCKS5 username
|
/** Maximum size of information that we can fit into SOCKS5 username
|
||||||
or password fields. */
|
or password fields. */
|
||||||
#define MAX_SOCKS5_AUTH_FIELD_SIZE 255
|
#define MAX_SOCKS5_AUTH_FIELD_SIZE 255
|
||||||
|
@ -2940,7 +2940,7 @@ connection_exit_connect(edge_connection_t *edge_conn)
|
|||||||
const tor_addr_t *addr;
|
const tor_addr_t *addr;
|
||||||
uint16_t port;
|
uint16_t port;
|
||||||
connection_t *conn = TO_CONN(edge_conn);
|
connection_t *conn = TO_CONN(edge_conn);
|
||||||
int socket_error = 0;
|
int socket_error = 0, result;
|
||||||
|
|
||||||
if ( (!connection_edge_is_rendezvous_stream(edge_conn) &&
|
if ( (!connection_edge_is_rendezvous_stream(edge_conn) &&
|
||||||
router_compare_to_my_exit_policy(&edge_conn->base_.addr,
|
router_compare_to_my_exit_policy(&edge_conn->base_.addr,
|
||||||
@ -2955,14 +2955,36 @@ connection_exit_connect(edge_connection_t *edge_conn)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
addr = &conn->addr;
|
#ifdef HAVE_SYS_UN_H
|
||||||
port = conn->port;
|
if (conn->socket_family != AF_UNIX) {
|
||||||
|
#else
|
||||||
|
{
|
||||||
|
#endif /* defined(HAVE_SYS_UN_H) */
|
||||||
|
addr = &conn->addr;
|
||||||
|
port = conn->port;
|
||||||
|
|
||||||
if (tor_addr_family(addr) == AF_INET6)
|
if (tor_addr_family(addr) == AF_INET6)
|
||||||
conn->socket_family = AF_INET6;
|
conn->socket_family = AF_INET6;
|
||||||
|
|
||||||
log_debug(LD_EXIT,"about to try connecting");
|
log_debug(LD_EXIT, "about to try connecting");
|
||||||
switch (connection_connect(conn, conn->address, addr, port, &socket_error)) {
|
result = connection_connect(conn, conn->address,
|
||||||
|
addr, port, &socket_error);
|
||||||
|
#ifdef HAVE_SYS_UN_H
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* In the AF_UNIX case, we expect to have already had conn->port = 1,
|
||||||
|
* tor_addr_make_unspec(conn->addr) (cf. the way we mark in the incoming
|
||||||
|
* case in connection_handle_listener_read()), and conn->address should
|
||||||
|
* have the socket path to connect to.
|
||||||
|
*/
|
||||||
|
tor_assert(conn->address && strlen(conn->address) > 0);
|
||||||
|
|
||||||
|
log_debug(LD_EXIT, "about to try connecting");
|
||||||
|
result = connection_connect_unix(conn, conn->address, &socket_error);
|
||||||
|
#endif /* defined(HAVE_SYS_UN_H) */
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (result) {
|
||||||
case -1: {
|
case -1: {
|
||||||
int reason = errno_to_stream_end_reason(socket_error);
|
int reason = errno_to_stream_end_reason(socket_error);
|
||||||
connection_edge_end(edge_conn, reason);
|
connection_edge_end(edge_conn, reason);
|
||||||
|
Loading…
Reference in New Issue
Block a user