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 {