summaryrefslogtreecommitdiff
path: root/src/or/connection.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/or/connection.c')
-rw-r--r--src/or/connection.c198
1 files changed, 145 insertions, 53 deletions
diff --git a/src/or/connection.c b/src/or/connection.c
index 6e754a0f7a..6a3cc7bec4 100644
--- a/src/or/connection.c
+++ b/src/or/connection.c
@@ -44,6 +44,7 @@
#include "router.h"
#include "transports.h"
#include "routerparse.h"
+#include "transports.h"
#ifdef USE_BUFFEREVENTS
#include <event2/event.h>
@@ -876,8 +877,11 @@ check_location_for_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)
+ 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->ControlSocketsGroupWritable)
flags |= CPD_GROUP_OK;
@@ -939,8 +943,8 @@ connection_listener_new(const struct sockaddr *listensockaddr,
const port_cfg_t *port_cfg)
{
listener_connection_t *lis_conn;
- connection_t *conn;
- tor_socket_t s; /* the socket we're going to make */
+ connection_t *conn = NULL;
+ tor_socket_t s = TOR_INVALID_SOCKET; /* the socket we're going to make */
or_options_t const *options = get_options();
#if defined(HAVE_PWD_H) && defined(HAVE_SYS_UN_H)
struct passwd *pw = NULL;
@@ -988,7 +992,7 @@ connection_listener_new(const struct sockaddr *listensockaddr,
/* We need to set IPV6_V6ONLY so that this socket can't get used for
* IPv4 connections. */
if (setsockopt(s,IPPROTO_IPV6, IPV6_V6ONLY,
- (void*)&one, sizeof(one))<0) {
+ (void*)&one, sizeof(one)) < 0) {
int e = tor_socket_errno(s);
log_warn(LD_NET, "Error setting IPV6_V6ONLY flag: %s",
tor_socket_strerror(e));
@@ -1004,7 +1008,6 @@ connection_listener_new(const struct sockaddr *listensockaddr,
helpfulhint = ". Is Tor already running?";
log_warn(LD_NET, "Could not bind to %s:%u: %s%s", address, usePort,
tor_socket_strerror(e), helpfulhint);
- tor_close_socket(s);
goto err;
}
@@ -1012,7 +1015,6 @@ connection_listener_new(const struct sockaddr *listensockaddr,
if (listen(s,SOMAXCONN) < 0) {
log_warn(LD_NET, "Could not listen on %s:%u: %s", address, usePort,
tor_socket_strerror(tor_socket_errno(s)));
- tor_close_socket(s);
goto err;
}
}
@@ -1061,7 +1063,6 @@ connection_listener_new(const struct sockaddr *listensockaddr,
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)));
- tor_close_socket(s);
goto err;
}
#ifdef HAVE_PWD_H
@@ -1070,12 +1071,10 @@ connection_listener_new(const struct sockaddr *listensockaddr,
if (pw == NULL) {
log_warn(LD_NET,"Unable to chown() %s socket: user %s not found.",
address, options->User);
- tor_close_socket(s);
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));
- tor_close_socket(s);
goto err;
}
}
@@ -1085,35 +1084,32 @@ connection_listener_new(const struct sockaddr *listensockaddr,
* platforms. */
if (chmod(address, 0660) < 0) {
log_warn(LD_FS,"Unable to make %s group-writable.", address);
- tor_close_socket(s);
goto err;
}
}
- if (listen(s,SOMAXCONN) < 0) {
+ if (listen(s, SOMAXCONN) < 0) {
log_warn(LD_NET, "Could not listen on %s: %s", address,
tor_socket_strerror(tor_socket_errno(s)));
- tor_close_socket(s);
goto err;
}
#else
(void)options;
#endif /* HAVE_SYS_UN_H */
} else {
- log_err(LD_BUG,"Got unexpected address family %d.",
- listensockaddr->sa_family);
- tor_assert(0);
+ log_err(LD_BUG, "Got unexpected address family %d.",
+ listensockaddr->sa_family);
+ tor_assert(0);
}
- if (set_socket_nonblocking(s) == -1) {
- tor_close_socket(s);
+ if (set_socket_nonblocking(s) == -1)
goto err;
- }
lis_conn = listener_connection_new(type, listensockaddr->sa_family);
conn = TO_CONN(lis_conn);
conn->socket_family = listensockaddr->sa_family;
conn->s = s;
+ s = TOR_INVALID_SOCKET; /* Prevent double-close */
conn->address = tor_strdup(address);
conn->port = gotPort;
tor_addr_copy(&conn->addr, &addr);
@@ -1149,7 +1145,6 @@ connection_listener_new(const struct sockaddr *listensockaddr,
if (connection_add(conn) < 0) { /* no space, forget it */
log_warn(LD_NET,"connection_add for listener failed. Giving up.");
- connection_free(conn);
goto err;
}
@@ -1168,6 +1163,11 @@ connection_listener_new(const struct sockaddr *listensockaddr,
return conn;
err:
+ if (SOCKET_OK(s))
+ tor_close_socket(s);
+ if (conn)
+ connection_free(conn);
+
return NULL;
}
@@ -1580,6 +1580,32 @@ connection_proxy_state_to_string(int state)
return states[state];
}
+/** Returns the global proxy type used by tor. Use this function for
+ * logging or high-level purposes, don't use it to fill the
+ * <b>proxy_type</b> field of or_connection_t; use the actual proxy
+ * protocol instead.*/
+static int
+get_proxy_type(void)
+{
+ const or_options_t *options = get_options();
+
+ if (options->HTTPSProxy)
+ return PROXY_CONNECT;
+ else if (options->Socks4Proxy)
+ return PROXY_SOCKS4;
+ else if (options->Socks5Proxy)
+ return PROXY_SOCKS5;
+ else if (options->ClientTransportPlugin)
+ return PROXY_PLUGGABLE;
+ else
+ return PROXY_NONE;
+}
+
+/* One byte for the version, one for the command, two for the
+ port, and four for the addr... and, one more for the
+ username NUL: */
+#define SOCKS4_STANDARD_BUFFER_SIZE (1 + 1 + 2 + 4 + 1)
+
/** Write a proxy request of <b>type</b> (socks4, socks5, https) to conn
* for conn->addr:conn->port, authenticating with the auth details given
* in the configuration (if available). SOCKS 5 and HTTP CONNECT proxies
@@ -1634,17 +1660,45 @@ connection_proxy_connect(connection_t *conn, int type)
}
case PROXY_SOCKS4: {
- unsigned char buf[9];
+ unsigned char *buf;
uint16_t portn;
uint32_t ip4addr;
+ size_t buf_size = 0;
+ char *socks_args_string = NULL;
- /* Send a SOCKS4 connect request with empty user id */
+ /* Send a SOCKS4 connect request */
if (tor_addr_family(&conn->addr) != AF_INET) {
log_warn(LD_NET, "SOCKS4 client is incompatible with IPv6");
return -1;
}
+ { /* If we are here because we are trying to connect to a
+ pluggable transport proxy, check if we have any SOCKS
+ arguments to transmit. If we do, compress all arguments to
+ a single string in 'socks_args_string': */
+
+ if (get_proxy_type() == PROXY_PLUGGABLE) {
+ socks_args_string =
+ pt_get_socks_args_for_proxy_addrport(&conn->addr, conn->port);
+ if (socks_args_string)
+ log_debug(LD_NET, "Sending out '%s' as our SOCKS argument string.",
+ socks_args_string);
+ }
+ }
+
+ { /* Figure out the buffer size we need for the SOCKS message: */
+
+ buf_size = SOCKS4_STANDARD_BUFFER_SIZE;
+
+ /* If we have a SOCKS argument string, consider its size when
+ calculating the buffer size: */
+ if (socks_args_string)
+ buf_size += strlen(socks_args_string);
+ }
+
+ buf = tor_malloc_zero(buf_size);
+
ip4addr = tor_addr_to_ipv4n(&conn->addr);
portn = htons(conn->port);
@@ -1652,9 +1706,23 @@ connection_proxy_connect(connection_t *conn, int type)
buf[1] = SOCKS_COMMAND_CONNECT; /* command */
memcpy(buf + 2, &portn, 2); /* port */
memcpy(buf + 4, &ip4addr, 4); /* addr */
- buf[8] = 0; /* userid (empty) */
- connection_write_to_buf((char *)buf, sizeof(buf), conn);
+ /* Next packet field is the userid. If we have pluggable
+ transport SOCKS arguments, we have to embed them
+ there. Otherwise, we use an empty userid. */
+ if (socks_args_string) { /* place the SOCKS args string: */
+ tor_assert(strlen(socks_args_string) > 0);
+ tor_assert(buf_size >=
+ SOCKS4_STANDARD_BUFFER_SIZE + strlen(socks_args_string));
+ strlcpy((char *)buf + 8, socks_args_string, buf_size - 8);
+ tor_free(socks_args_string);
+ } else {
+ buf[8] = 0; /* no userid */
+ }
+
+ connection_write_to_buf((char *)buf, buf_size, conn);
+ tor_free(buf);
+
conn->proxy_state = PROXY_SOCKS4_WANT_CONNECT_OK;
break;
}
@@ -1666,8 +1734,13 @@ connection_proxy_connect(connection_t *conn, int type)
buf[0] = 5; /* version */
+ /* We have to use SOCKS5 authentication, if we have a
+ Socks5ProxyUsername or if we want to pass arguments to our
+ pluggable transport proxy: */
+ if ((options->Socks5ProxyUsername) ||
+ (get_proxy_type() == PROXY_PLUGGABLE &&
+ (get_socks_args_by_bridge_addrport(&conn->addr, conn->port)))) {
/* number of auth methods */
- if (options->Socks5ProxyUsername) {
buf[1] = 2;
buf[2] = 0x00; /* no authentication */
buf[3] = 0x02; /* rfc1929 Username/Passwd auth */
@@ -1861,15 +1934,49 @@ connection_read_proxy_handshake(connection_t *conn)
unsigned char buf[1024];
size_t reqsize, usize, psize;
const char *user, *pass;
+ char *socks_args_string = NULL;
+
+ if (get_proxy_type() == PROXY_PLUGGABLE) {
+ socks_args_string =
+ pt_get_socks_args_for_proxy_addrport(&conn->addr, conn->port);
+ if (!socks_args_string) {
+ log_warn(LD_NET, "Could not create SOCKS args string.");
+ ret = -1;
+ break;
+ }
+
+ log_debug(LD_NET, "SOCKS5 arguments: %s", socks_args_string);
+ tor_assert(strlen(socks_args_string) > 0);
+ tor_assert(strlen(socks_args_string) <= MAX_SOCKS5_AUTH_SIZE_TOTAL);
+
+ if (strlen(socks_args_string) > MAX_SOCKS5_AUTH_FIELD_SIZE) {
+ user = socks_args_string;
+ usize = MAX_SOCKS5_AUTH_FIELD_SIZE;
+ pass = socks_args_string + MAX_SOCKS5_AUTH_FIELD_SIZE;
+ psize = strlen(socks_args_string) - MAX_SOCKS5_AUTH_FIELD_SIZE;
+ } else {
+ user = socks_args_string;
+ usize = strlen(socks_args_string);
+ pass = "\0";
+ psize = 1;
+ }
+ } else if (get_options()->Socks5ProxyUsername) {
+ user = get_options()->Socks5ProxyUsername;
+ pass = get_options()->Socks5ProxyPassword;
+ tor_assert(user && pass);
+ usize = strlen(user);
+ psize = strlen(pass);
+ } else {
+ log_err(LD_BUG, "We entered %s for no reason!", __func__);
+ tor_fragile_assert();
+ ret = -1;
+ break;
+ }
- user = get_options()->Socks5ProxyUsername;
- pass = get_options()->Socks5ProxyPassword;
- tor_assert(user && pass);
-
- /* XXX len of user and pass must be <= 255 !!! */
- usize = strlen(user);
- psize = strlen(pass);
- tor_assert(usize <= 255 && psize <= 255);
+ /* Username and password lengths should have been checked
+ above and during torrc parsing. */
+ tor_assert(usize <= MAX_SOCKS5_AUTH_FIELD_SIZE &&
+ psize <= MAX_SOCKS5_AUTH_FIELD_SIZE);
reqsize = 3 + usize + psize;
buf[0] = 1; /* negotiation version */
@@ -1878,6 +1985,9 @@ connection_read_proxy_handshake(connection_t *conn)
buf[2 + usize] = psize;
memcpy(buf + 3 + usize, pass, psize);
+ if (socks_args_string)
+ tor_free(socks_args_string);
+
connection_write_to_buf((char *)buf, reqsize, conn);
conn->proxy_state = PROXY_SOCKS5_WANT_AUTH_RFC1929_OK;
@@ -3288,8 +3398,8 @@ connection_outbuf_too_full(connection_t *conn)
/** Try to flush more bytes onto <b>conn</b>-\>s.
*
- * This function gets called either from conn_write() in main.c
- * when poll() has declared that conn wants to write, or below
+ * This function gets called either from conn_write_callback() in main.c
+ * when libevent tells us that conn wants to write, or below
* from connection_write_to_buf() when an entire TLS record is ready.
*
* Update <b>conn</b>-\>timestamp_lastwritten to now, and call flush_buf
@@ -4366,7 +4476,7 @@ get_proxy_addrport(tor_addr_t *addr, uint16_t *port, int *proxy_type,
options->Bridges) {
const transport_t *transport = NULL;
int r;
- r = find_transport_by_bridge_addrport(&conn->addr, conn->port, &transport);
+ r = get_transport_by_bridge_addrport(&conn->addr, conn->port, &transport);
if (r<0)
return -1;
if (transport) { /* transport found */
@@ -4381,24 +4491,6 @@ get_proxy_addrport(tor_addr_t *addr, uint16_t *port, int *proxy_type,
return 0;
}
-/** Returns the global proxy type used by tor. */
-static int
-get_proxy_type(void)
-{
- const or_options_t *options = get_options();
-
- if (options->HTTPSProxy)
- return PROXY_CONNECT;
- else if (options->Socks4Proxy)
- return PROXY_SOCKS4;
- else if (options->Socks5Proxy)
- return PROXY_SOCKS5;
- else if (options->ClientTransportPlugin)
- return PROXY_PLUGGABLE;
- else
- return PROXY_NONE;
-}
-
/** Log a failed connection to a proxy server.
* <b>conn</b> is the connection we use the proxy server for. */
void