[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[tor-dev] Tor + Apache Traffic Server w/ SOCKS - works now!
So I've been looking for a long time for something modern to sit between my browser and Tor -- something modern, capable, and efficient (i.e. doesn't fork every connection).
Years ago Yahoo got some proxy software from an acquisition, a few years later they made it open source as Apache Traffic Server (
http://trafficserver.apache.org/), and today its the backbone of Yahoo's infrastructure. They have a number of full time engineers that work on it full time, they use it in production, and they are implementing cutting edge features like IPv6, SPDY, and HTTP/2 support.
SOCKS is was one of the legacy features of Apache Traffic Server. However, it hasn't been maintained. If you build from git right now you'll find SOCKS support completely broken at least four ways (a couple bad asserts, wrong byte order, and an uninitialized field). They took the documentation on the SOCKS feature out a while ago but never got around to removing the code.
Since it was there I spent some time over the weekend and fixed it. There are still some issues around SOCKS still but it works well enough that you can surf though tor with it. If there is interest in it here I'd be happy to put together a how-to for Linux and MacOS to get it built and configured.
I'd also like to encourage people to make some noise - Yahoo does have SOCKS servers internally but they don't test using Traffic Server with them because they don't think anyone uses the feature (and they are right, there is no way the code works for anyone in the present state). But if there was interest then maybe they'd keep the code fresh going forward.
diff --git a/doc/reference/configuration/records.config.en.rst b/doc/reference/configuration/records.config.en.rst
index a9a2c68..8b03894 100644
--- a/doc/reference/configuration/records.config.en.rst
+++ b/doc/reference/configuration/records.config.en.rst
@@ -2639,6 +2639,74 @@ Plug-in Configuration
on a dedicated thread pool, freeing the network threads to service
additional requests.
+SOCKS Processor
+===============
+
+.. ts:cv:: CONFIG proxy.config.socks.socks_needed INT 0
+
+ Enables (``1``) or disables (``0``) the SOCKS processor
+
+.. ts:cv:: CONFIG proxy.config.socks.socks_version INT 4
+
+ Specifies the SOCKS version (``4``) or (``5``)
+
+.. ts:cv:: CONFIG proxy.config.socks.socks_config_file STRING socks.config
+
+ The socks_onfig file allows you to specify ranges of IP addresses
+ that will not be relayed to the SOCKS server. It can also be used
+ to configure AUTH information for SOCKSv5 servers.
+
+.. ts:cv:: CONFIG proxy.config.socks.socks_timeout INT 100
+
+ The activity timeout value (in seconds) for SOCKS server connections.
+
+.. ts:cv:: CONFIG proxy.config.socks.server_connect_timeout INT 10
+
+ The timeout value (in seconds) for SOCKS server connection attempts.
+
+.. ts:cv:: CONFIG proxy.config.socks.per_server_connection_attempts INT 1
+
+ The total number of connection attempts allowed per SOCKS server,
+ if multiple servers are used.
+
+.. ts:cv:: CONFIG proxy.config.socks.connection_attempts INT 4
+
+ The total number of connection attempts allowed to a SOCKS server
+ Traffic Server bypasses the server or fails the request
+
+.. ts:cv:: CONFIG proxy.config.socks.server_retry_timeout INT 300
+
+ The timeout value (in seconds) for SOCKS server connection retry attempts.
+
+.. ts:cv:: CONFIG proxy.config.socks.default_servers STRING
+
+ Default list of SOCKS servers and their ports.
+
+.. ts:cv:: CONFIG proxy.config.socks.server_retry_time INT 300
+
+ The amount of time allowed between connection retries to a SOCKS
+ server that is unavailable.
+
+.. ts:cv:: CONFIG proxy.config.socks.server_fail_threshold INT 2
+
+ The number of times the connection to the SOCKS server can fail
+ before Traffic Server considers the server unavailable.
+
+.. ts:cv:: CONFIG proxy.config.socks.accept_enabled INT 0
+
+ Enables (1) or disables (0) the SOCKS proxy option. As a SOCKS
+ proxy, Traffic Server receives SOCKS traffic (usually on port
+ 1080) and forwards all requests directly to the SOCKS server.
+
+.. ts:cv:: CONFIG proxy.config.socks.accept_port INT 1080
+
+ Specifies the port on which Traffic Server accepts SOCKS traffic.
+
+.. ts:cv:: CONFIG proxy.config.socks.http_port INT 80
+
+ Specifies the port on which Traffic Server accepts HTTP proxy requests
+ over SOCKS connections..
+
Sockets
=======
diff --git a/iocore/net/Socks.cc b/iocore/net/Socks.cc
index a0350f6..a253842 100644
--- a/iocore/net/Socks.cc
+++ b/iocore/net/Socks.cc
@@ -54,20 +54,12 @@ SocksEntry::init(ProxyMutex *m, SocksNetVC *vc, unsigned char socks_support, uns
SET_HANDLER(&SocksEntry::startEvent);
- ats_ip_copy(&target_addr, vc->get_local_addr());
-
#ifdef SOCKS_WITH_TS
req_data.hdr = 0;
req_data.hostname_str = 0;
req_data.api_info = 0;
req_data.xact_start = time(0);
- assert(ats_is_ip4(&target_addr));
- ats_ip_copy(&req_data.dest_ip, &target_addr);
-
- // we dont have information about the source. set to destination's
- ats_ip_copy(&req_data.src_ip, &target_addr);
-
server_params = SocksServerConfig::acquire();
#endif
@@ -133,14 +125,6 @@ SocksEntry::findServer()
void
SocksEntry::free()
{
- MUTEX_TRY_LOCK(lock, action_.mutex, this_ethread());
- if (lock.is_locked()) {
- // Socks continuation share the user's lock
- // so acquiring a lock shouldn't fail
- ink_assert(0);
- return;
- }
-
if (timeout)
timeout->cancel(this);
@@ -234,6 +218,14 @@ SocksEntry::mainEvent(int event, void *data)
int ret = EVENT_DONE;
int n_bytes = 0;
unsigned char *p;
+ ip_port_text_buffer sbuff;
+ ip_port_text_buffer tbuff;
+
+ Debug("Socks", "SocksEntry::mainEvent event=%i server=%s target=%s",
+ event,
+ ats_ip_nptop(server_addr, sbuff, sizeof(sbuff)),
+ ats_ip_nptop(target_addr, tbuff, sizeof(tbuff))
+ );
switch (event) {
case NET_EVENT_OPEN:
@@ -245,40 +237,54 @@ SocksEntry::mainEvent(int event, void *data)
if (auth_handler) {
n_bytes = invokeSocksAuthHandler(auth_handler, SOCKS_AUTH_OPEN, p);
} else {
- // Debug("Socks", " Got NET_EVENT_OPEN to SOCKS server\n");
-
- p[n_bytes++] = version;
- p[n_bytes++] = (socks_cmd == NORMAL_SOCKS) ? SOCKS_CONNECT : socks_cmd;
- ts = ntohs(ats_ip_port_cast(&server_addr));
+ ts = ats_ip_port_cast(&target_addr);
if (version == SOCKS5_VERSION) {
- p[n_bytes++] = 0; // Reserved
- if (ats_is_ip4(&server_addr)) {
- p[n_bytes++] = 1; // IPv4 addr
- memcpy(p + n_bytes, &server_addr.sin.sin_addr, 4);
- n_bytes += 4;
- } else if (ats_is_ip6(&server_addr)) {
- p[n_bytes++] = 4; // IPv6 addr
- memcpy(p + n_bytes, &server_addr.sin6.sin6_addr, TS_IP6_SIZE);
+ // Socks Version (VER)
+ p[n_bytes++] = SOCKS5_VERSION;
+ // Command (CMD)
+ p[n_bytes++] = (socks_cmd == NORMAL_SOCKS) ? SOCKS_CONNECT : socks_cmd;
+ // Reserved (RSV)
+ p[n_bytes++] = 0;
+ if (ats_is_ip4(&target_addr)) {
+ // Address Type (ATYP)
+ p[n_bytes++] = SOCKS_ATYPE_IPV4;
+ // Destination Address (DST.ADDR)
+ memcpy(p + n_bytes, &target_addr.sin.sin_addr, TS_IP4_SIZE);
+ n_bytes += TS_IP4_SIZE;
+ } else if (ats_is_ip6(&target_addr)) {
+ // Address Type (ATYP)
+ p[n_bytes++] = SOCKS_ATYPE_IPV6;
+ // Destination Address (DST.ADDR)
+ memcpy(p + n_bytes, &target_addr.sin6.sin6_addr, TS_IP6_SIZE);
n_bytes += TS_IP6_SIZE;
} else {
Debug("Socks", "SOCKS supports only IP addresses.");
+ // Should abort if we reach here
}
+ // Destination Port DST.PORT
+ memcpy(p + n_bytes, &ts, 2);
+ n_bytes += 2;
}
- memcpy(p + n_bytes, &ts, 2);
- n_bytes += 2;
-
if (version == SOCKS4_VERSION) {
- if (ats_is_ip4(&server_addr)) {
- // for socks4, ip addr is after the port
- memcpy(p + n_bytes, &server_addr.sin.sin_addr, 4);
- n_bytes += 4;
-
- p[n_bytes++] = 0; // NULL
+ // Socks Version (VN)
+ p[n_bytes++] = SOCKS4_VERSION;
+ // Command (CD)
+ p[n_bytes++] = (socks_cmd == NORMAL_SOCKS) ? SOCKS_CONNECT : socks_cmd;
+ // Destination Port DSTPORT
+ memcpy(p + n_bytes, &ts, 2);
+ n_bytes += 2;
+ if (ats_is_ip4(&target_addr)) {
+ // Destination IP
+ memcpy(p + n_bytes, &target_addr.sin.sin_addr, TS_IP4_SIZE);
+ n_bytes += TS_IP4_SIZE;
} else {
Debug("Socks", "SOCKS v4 supports only IPv4 addresses.");
+ // Should abort if we reach here
}
+ // Terminator Byte (NULL)
+ p[n_bytes++] = 0;
}
}
diff --git a/iocore/net/UnixNetProcessor.cc b/iocore/net/UnixNetProcessor.cc
index fdc58ab..5368116 100644
--- a/iocore/net/UnixNetProcessor.cc
+++ b/iocore/net/UnixNetProcessor.cc
@@ -224,6 +224,8 @@ UnixNetProcessor::connect_re_internal(Continuation *cont, sockaddr const *target
Debug("Socks", "Using Socks ip: %s\n", ats_ip_nptop(target, buff, sizeof(buff)));
socksEntry = socksAllocator.alloc();
socksEntry->init(cont->mutex, vc, opt->socks_support, opt->socks_version); /*XXXX remove last two args */
+ ats_ip_copy(&socksEntry->target_addr, target); // Real address we want the socks server to connect to
+ ats_ip_copy(&socksEntry->req_data.dest_ip, target);
socksEntry->action_ = cont;
cont = socksEntry;
if (!ats_is_ip(&socksEntry->server_addr)) {
diff --git a/lib/ts/ink_inet.h b/lib/ts/ink_inet.h
index 553f444..9c5400a 100644
--- a/lib/ts/ink_inet.h
+++ b/lib/ts/ink_inet.h
@@ -181,7 +181,9 @@ inkcoreapi uint32_t ats_inet_addr(const char *s);
const char *ats_ip_ntop(const struct sockaddr *addr, char *dst, size_t size);
-// --
+/// Size in bytes of an IPv4 address.
+static size_t const TS_IP4_SIZE = sizeof(in_addr);
+
/// Size in bytes of an IPv6 address.
static size_t const TS_IP6_SIZE = sizeof(in6_addr);
diff --git a/proxy/config/records.config.default.in b/proxy/config/records.config.default.in
index 8a11063..02b6b9c 100644
--- a/proxy/config/records.config.default.in
+++ b/proxy/config/records.config.default.in
@@ -196,3 +196,23 @@ CONFIG proxy.config.cluster.cluster_port INT 8086
CONFIG proxy.config.cluster.rsport INT 8088
CONFIG proxy.config.cluster.mcport INT 8089
CONFIG proxy.config.cluster.mc_group_addr STRING 224.0.1.37
+
+##############################################################################
+# SOCKS Processor. Docs:
+# https://docs.trafficserver.apache.org/records.config#socks_processor
+##############################################################################
+CONFIG proxy.config.socks.socks_needed INT 0
+CONFIG proxy.config.socks.socks_version INT 4
+CONFIG proxy.config.socks.socks_config_file STRING socks.config
+CONFIG proxy.config.socks.socks_timeout INT 100
+CONFIG proxy.config.socks.server_connect_timeout INT 10
+CONFIG proxy.config.socks.per_server_connection_attempts INT 1
+CONFIG proxy.config.socks.connection_attempts INT 4
+CONFIG proxy.config.socks.server_retry_timeout INT 300
+CONFIG proxy.config.socks.default_servers STRING
+CONFIG proxy.config.socks.server_retry_time INT 300
+CONFIG proxy.config.socks.server_fail_threshold INT 2
+CONFIG proxy.config.socks.accept_enabled INT 0
+CONFIG proxy.config.socks.accept_port INT 1080
+CONFIG proxy.config.socks.http_port INT 80
+
diff --git a/proxy/config/socks.config.default b/proxy/config/socks.config.default
index cd9e06a..bc32d3b 100644
--- a/proxy/config/socks.config.default
+++ b/proxy/config/socks.config.default
@@ -16,13 +16,17 @@ no_socks 123.14.15.1 - 123.14.17.4, 113.14.18.2
no_socks 123.14.30.1 - 123.14.63.4, 122.43.15.2
no_socks 123.14.84.1 - 123.14.89.4, 109.32.15.2
+# THIS ENTRY REQUIRED: Otherwise Traffic Server tries to connect
+# to 127.0.0.0/8 through the SOCKS proxy
+no_socks 127.0.0.0 - 127.255.255.255
+
#
# Authentication for SOCKS 5
# We currently support Username/Password authentication
# Format for username/password used by traffic_server when it connects to
# the SOCKS server:
# auth u <user_name> <pasword>
-# The letter u says it is of type username/password.
+# The letter u says it is of type username/password.
# e.g:
# auth u traffic_server inktomi
#
@@ -47,3 +51,4 @@ no_socks 123.14.84.1 - 123.14.89.4, 109.32.15.2
# dest_ip=216.32.0.0-216.32.255.255 parent="socks1:4080; socks2:1080" round_robin=strict
#
########################################################################################
+
_______________________________________________
tor-dev mailing list
tor-dev@xxxxxxxxxxxxxxxxxxxx
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-dev