From 0e9359ee26041e4c78f441fb3217d84d046de4cd Mon Sep 17 00:00:00 2001
From: zxcvbn4038 <zxcvbn4038@gmail.com>
Date: Mon, 4 May 2015 02:21:23 -0400
Subject: [PATCH 1/1] Partially restore SOCKS functionality, it connects the
 right place and asks for the correct address now

---
 doc/reference/configuration/records.config.en.rst | 68 +++++++++++++++++++++
 iocore/net/Socks.cc                               | 74 ++++++++++++++---------
 iocore/net/UnixNetProcessor.cc                    |  2 +
 lib/ts/ink_inet.h                                 |  4 +-
 proxy/config/records.config.default.in            | 20 ++++++
 5 files changed, 137 insertions(+), 31 deletions(-)

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..996d14b 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
 
@@ -234,6 +226,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 +245,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
+
-- 
1.8.2.1

