Package: tinyproxy
Version: 1.6.3-2
Severity: wishlist

I've written a patch for tinyproxy that allows one to support
socks4 and socks5 proxies upstream.

A short explanation of the new feature: it adds some extra syntax to
the "upstream" statement, namely "http" "socks4" and "socks5" (with
"http" by default if omitted, to ensure backwards compatibility)

The new syntax is:

    upstream [http|socks4|socks5] host:port (rule to match)

etc.

I've been using this for a few months and it works fine for me.

--------------

The attached patch applies cleanly to both the original (1.6.3) source
code and to the debian source code (1.6.3-2)

Hope this helps...

Best, Gonzalo


-- System Information:
Debian Release: testing/unstable
  APT prefers testing
  APT policy: (990, 'testing'), (500, 'unstable')
Architecture: amd64 (x86_64)
Shell:  /bin/sh linked to /bin/bash
Kernel: Linux 2.6.16-2-em64t-p4-smp
Locale: LANG=en_US.UTF-8, LC_CTYPE=en_US.UTF-8 (charmap=UTF-8)

Versions of packages tinyproxy depends on:
ii  libc6                        2.3.6.ds1-4 GNU C Library: Shared libraries
ii  logrotate                    3.7.1-3     Log rotation utility

tinyproxy recommends no packages.

-- no debconf information
--- tinyproxy-1.6.3-orig/src/grammar.y  2004-08-06 13:23:50.000000000 -0300
+++ tinyproxy-1.6.3/src/grammar.y       2006-07-18 22:52:09.000000000 -0300
@@ -57,6 +57,9 @@
 %token KW_STATPAGE
 %token KW_VIA_PROXY_NAME
 
+/* proxy types */
+%token KW_PROXY_HTTP KW_PROXY_SOCKS4 KW_PROXY_SOCKS5
+
 /* yes/no switches */
 %token KW_YES KW_NO
 
@@ -75,6 +78,7 @@
 %type <cptr> network_address
 %type <cptr> unique_address
 %type <num> loglevels
+%type <num> upstream_proxy
 
 %%
 
@@ -167,18 +171,18 @@
                  log_message(LOG_WARNING, "X-Tinyproxy header support was not 
compiled in.");
 #endif
           }
-        | KW_UPSTREAM unique_address ':' NUMBER
+        | upstream_proxy unique_address ':' NUMBER
           {
 #ifdef UPSTREAM_SUPPORT
-                 upstream_add($2, $4, NULL);
+                 upstream_add($2, $4, NULL, $1);
 #else
                   log_message(LOG_WARNING, "Upstream proxy support was not 
compiled in.");
 #endif
           }
-       | KW_UPSTREAM unique_address ':' NUMBER STRING
+       | upstream_proxy unique_address ':' NUMBER STRING
          {
 #ifdef UPSTREAM_SUPPORT
-                 upstream_add($2, $4, $5);
+                 upstream_add($2, $4, $5, $1);
 #else
                   log_message(LOG_WARNING, "Upstream proxy support was not 
compiled in.");
 #endif
@@ -186,7 +190,7 @@
        | KW_NO KW_UPSTREAM STRING
          {
 #ifdef UPSTREAM_SUPPORT
-                 upstream_add(NULL, 0, $3);
+                 upstream_add(NULL, 0, $3, 0);
 #else
                   log_message(LOG_WARNING, "Upstream proxy support was not 
compiled in.");
 #endif
@@ -221,6 +225,13 @@
          }
        ;
 
+upstream_proxy
+        : KW_UPSTREAM KW_PROXY_HTTP     { $$ = HTTP_TYPE; }
+        | KW_UPSTREAM KW_PROXY_SOCKS4   { $$ = SOCKS4_TYPE; }
+        | KW_UPSTREAM KW_PROXY_SOCKS5   { $$ = SOCKS5_TYPE; }
+        | KW_UPSTREAM                   { $$ = HTTP_TYPE; }
+        ;
+
 loglevels
         : KW_LOG_CRITICAL               { $$ = LOG_CRIT; }
         | KW_LOG_ERROR                  { $$ = LOG_ERR; }
--- tinyproxy-1.6.3-orig/src/reqs.c     2004-08-06 13:56:55.000000000 -0300
+++ tinyproxy-1.6.3/src/reqs.c  2006-07-19 13:15:07.000000000 -0300
@@ -59,9 +59,11 @@
 #ifdef UPSTREAM_SUPPORT
 #  define UPSTREAM_CONFIGURED() (config.upstream_list != NULL)
 #  define UPSTREAM_HOST(host) upstream_get(host)
+#  define UPSTREAM_IS_HTTP(conn) (conn->upstream_proxy != NULL && 
conn->upstream_proxy->type == HTTP_TYPE)
 #else
 #  define UPSTREAM_CONFIGURED() (0)
 #  define UPSTREAM_HOST(host) (NULL)
+#  define UPSTREAM_IS_HTTP(up) (0)
 #endif
 
 /*
@@ -311,11 +313,21 @@
 #endif /* TRANSPARENT_PROXY */
 
 #ifdef UPSTREAM_SUPPORT
+char *
+proxy_type_name(proxy_type type)
+{
+    switch(type) {
+        case HTTP_TYPE: return "http";
+        case SOCKS4_TYPE: return "socks4";
+        case SOCKS5_TYPE: return "socks5";
+        default: return "unknown";
+    }
+}
 /*
  * Add an entry to the upstream list
  */
 void
-upstream_add(const char *host, int port, const char *domain)
+upstream_add(const char *host, int port, const char *domain, proxy_type type)
 {
        char *ptr;
        struct upstream *up = safemalloc(sizeof (struct upstream));
@@ -325,6 +337,8 @@
                return;
        }
 
+       up->type = type;
+
        up->host = up->domain = NULL;
        up->ip = up->mask = 0;
 
@@ -337,7 +351,7 @@
                up->host = safestrdup(host);
                up->port = port;
 
-               log_message(LOG_INFO, "Added upstream %s:%d for [default]", 
host, port);
+               log_message(LOG_INFO, "Added upstream %s %s:%d for [default]", 
proxy_type_name(type), host, port);
        } else if (host == NULL) {
                if (!domain || domain[0] == '\0') {
                        log_message(LOG_WARNING, "Nonsense no-upstream rule: 
empty domain");
@@ -375,8 +389,8 @@
                up->port = port;
                up->domain = safestrdup(domain);
 
-               log_message(LOG_INFO, "Added upstream %s:%d for %s",
-                           host, port, domain);
+               log_message(LOG_INFO, "Added upstream %s %s:%d for %s",
+                           proxy_type_name(type), host, port, domain);
        }
 
        if (!up->domain && !up->ip) { /* always add default to end */
@@ -456,8 +470,8 @@
                up = NULL;
 
        if (up)
-               log_message(LOG_INFO, "Found proxy %s:%d for %s",
-                               up->host, up->port, host);
+               log_message(LOG_INFO, "Found proxy %s %s:%d for %s",
+                               proxy_type_name(up->type), up->host, up->port, 
host);
        else
                log_message(LOG_INFO, "No proxy for %s", host);
 
@@ -1069,10 +1083,10 @@
        /*
         * Don't send headers if there's already an error, if the request was
         * a stats request, or if this was a CONNECT method (unless upstream
-        * proxy is in use.)
+        * http proxy is in use.)
         */
        if (connptr->server_fd == -1 || connptr->show_stats
-           || (connptr->connect_method && (connptr->upstream_proxy == NULL))) {
+           || (connptr->connect_method && ! UPSTREAM_IS_HTTP(connptr))) {
                log_message(LOG_INFO, "Not sending client headers to remote 
machine");
                return 0;
        }
@@ -1394,6 +1408,87 @@
        return;
 }
 
+static int
+connect_to_upstream_proxy(struct conn_s *connptr, struct request_s *request)
+{
+       int len;
+       unsigned char buff[512]; /* won't use more than 7 + 255 */
+       unsigned short port;
+       struct hostent *host;
+       struct upstream *cur_upstream = connptr->upstream_proxy;
+
+       log_message(LOG_CONN,
+                   "Established connection to %s proxy \"%s\" using file 
descriptor %d.",
+                   proxy_type_name(cur_upstream->type), cur_upstream->host, 
connptr->server_fd);
+
+       if (cur_upstream->type == SOCKS4_TYPE) {
+
+               buff[0] = 4; // socks version
+               buff[1] = 1; // connect command
+               port = htons(request->port);
+               memcpy(&buff[2], &port, 2); // dest port
+               host = gethostbyname(request->host);
+               memcpy(&buff[4], host->h_addr_list[0], 4); // dest ip
+               buff[8] = 0; // user
+               if (9 != safe_write(connptr->server_fd, buff, 9))
+                       return -1;
+               if (8 != safe_read(connptr->server_fd, buff, 8))
+                       return -1;
+               if (buff[0]!=0 || buff[1]!=90)
+                       return -1;
+
+       } else if (cur_upstream->type == SOCKS5_TYPE) {
+
+               /* init */
+               buff[0] = 5; // socks version
+               buff[1] = 1; // number of methods
+               buff[2] = 0; // no auth method
+               if (3 != safe_write(connptr->server_fd, buff, 3))
+                       return -1;
+               if (2 != safe_read(connptr->server_fd, buff, 2))
+                       return -1;
+               if (buff[0]!=5 || buff[1]!=0)
+                       return -1;
+               /* connect */
+               buff[0] = 5; // socks version
+               buff[1] = 1; // connect
+               buff[2] = 0; // reserved
+               buff[3] = 3; // domainname
+               len=strlen(request->host);
+               if(len>255)
+                       return -1;
+               buff[4] = len; // length of domainname
+               memcpy(&buff[5], request->host, len); // dest ip
+               port = htons(request->port);
+               memcpy(&buff[5+len], &port, 2); // dest port
+               if (7+len != safe_write(connptr->server_fd, buff, 7+len))
+                       return -1;
+               if (4 != safe_read(connptr->server_fd, buff, 4))
+                       return -1;
+               if (buff[0]!=5 || buff[1]!=0)
+                       return -1;
+               switch(buff[3]) {
+                       case 1: len=4; break; // ip v4
+                       case 4: len=16; break; // ip v6
+                       case 3: // domainname
+                               if (1 != safe_read(connptr->server_fd, buff, 1))
+                                       return -1;
+                               len = buff[0]; /* max = 255 */
+                               break;
+                       default: return -1;
+               }
+               if (2+len != safe_read(connptr->server_fd, buff, 2+len))
+                       return -1;
+       } else {
+               return -1;
+       }
+                
+       if (connptr->connect_method)
+               return 0;
+
+       return establish_http_connection(connptr, request);
+}
+
 /*
  * Establish a connection to the upstream proxy server.
  */
@@ -1431,6 +1526,9 @@
                return -1;
        }
 
+       if (cur_upstream->type != HTTP_TYPE)
+               return connect_to_upstream_proxy(connptr, request);
+
        log_message(LOG_CONN,
                    "Established connection to upstream proxy \"%s\" using file 
descriptor %d.",
                    cur_upstream->host, connptr->server_fd);
@@ -1600,7 +1698,7 @@
                return;
        }
 
-       if (!connptr->connect_method || (connptr->upstream_proxy != NULL)) {
+       if (!connptr->connect_method || UPSTREAM_IS_HTTP(connptr)) {
                if (process_server_headers(connptr) < 0) {
                        if (connptr->error_variables)
                                send_http_error_message(connptr);
--- tinyproxy-1.6.3-orig/src/reqs.h     2004-08-06 13:23:51.000000000 -0300
+++ tinyproxy-1.6.3/src/reqs.h  2006-07-18 22:38:18.000000000 -0300
@@ -21,6 +21,6 @@
 
 extern void handle_connection(int fd);
 extern void add_connect_port_allowed(int port);
-extern void upstream_add(const char *host, int port, const char *domain);
+extern void upstream_add(const char *host, int port, const char *domain, 
proxy_type type);
 
 #endif
--- tinyproxy-1.6.3-orig/src/scanner.l  2004-08-06 13:23:51.000000000 -0300
+++ tinyproxy-1.6.3/src/scanner.l       2006-07-19 13:25:25.000000000 -0300
@@ -60,6 +60,11 @@
        { "defaulterrorfile",    KW_DEFAULT_ERRORPAGE },
        { "statfile",            KW_STATPAGE },
 
+       /* proxy types */
+       { "http",               KW_PROXY_HTTP },
+       { "socks4",             KW_PROXY_SOCKS4 },
+       { "socks5",             KW_PROXY_SOCKS5 },
+
         /* loglevel and the settings */
         { "loglevel",            KW_LOGLEVEL },
        { "critical",            KW_LOG_CRITICAL },
--- tinyproxy-1.6.3-orig/src/tinyproxy.h        2004-08-06 13:56:55.000000000 
-0300
+++ tinyproxy-1.6.3/src/tinyproxy.h     2006-07-18 22:37:00.000000000 -0300
@@ -29,12 +29,14 @@
  * Even if upstream support is not compiled into tinyproxy, this
  * structure still needs to be defined.
  */
+typedef enum {HTTP_TYPE, SOCKS4_TYPE, SOCKS5_TYPE} proxy_type;
 struct upstream {
        struct upstream *next;
        char *domain; /* optional */
        char *host;
        int port;
        in_addr_t ip, mask;
+       proxy_type type;
 };
 
 struct config_s {

Reply via email to