[tor-dev] Tor + Apache Traffic Server w/ SOCKS - works now!

CJ Ess zxcvbn4038 at gmail.com
Tue May 5 13:47:32 UTC 2015


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.

I'm including a copy of the patch with this e-mail just to get it out. You
can pull their git repository (https://github.com/apache/trafficserver) and
apply it to the master master branch.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.torproject.org/pipermail/tor-dev/attachments/20150505/a14e383e/attachment-0001.html>
-------------- next part --------------
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
 #
 ########################################################################################
+


More information about the tor-dev mailing list