diff options
author | Gonzalo Tornaria <tornaria@math.utexas.edu> | 2016-12-20 21:30:43 +0000 |
---|---|---|
committer | rofl0r <rofl0r@users.noreply.github.com> | 2018-02-06 16:11:39 +0000 |
commit | 8906b0734e5c61016d9d4090507f010b2006292d (patch) | |
tree | 73eea974f5a292516e1ffd85ed44ddeae1b34764 /src | |
parent | 116e59e93346ddbe08f56f8c7e8bd648690c0242 (diff) |
add SOCKS upstream proxy support (socks4/socks5)
original patch submitted in 2006 to debian mailing list:
https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=392848%29#12
this version was rebased to git and updated by Russ Dill <russ.dill@gmail.com>
in 2015 (the original patch used a different config file format).
as discussed in #40.
commit message by @rofl0r.
Diffstat (limited to 'src')
-rw-r--r-- | src/conf.c | 34 | ||||
-rw-r--r-- | src/reqs.c | 93 | ||||
-rw-r--r-- | src/upstream.c | 31 | ||||
-rw-r--r-- | src/upstream.h | 5 |
4 files changed, 146 insertions, 17 deletions
@@ -160,6 +160,8 @@ static HANDLE_FUNC (handle_xtinyproxy); #ifdef UPSTREAM_SUPPORT static HANDLE_FUNC (handle_upstream); +static HANDLE_FUNC (handle_upstream4); +static HANDLE_FUNC (handle_upstream5); static HANDLE_FUNC (handle_upstream_no); #endif @@ -257,6 +259,14 @@ struct { BEGIN "(upstream)" WS "(" IP "|" ALNUM ")" ":" INT "(" WS STR ")?" END, handle_upstream, NULL }, + { + BEGIN "(upstream4)" WS "(" IP "|" ALNUM ")" ":" INT "(" WS STR + ")?" END, handle_upstream4, NULL + }, + { + BEGIN "(upstream5)" WS "(" IP "|" ALNUM ")" ":" INT "(" WS STR + ")?" END, handle_upstream5, NULL + }, #endif /* loglevel */ STDCONF ("loglevel", "(critical|error|warning|notice|connect|info)", @@ -1066,7 +1076,8 @@ static HANDLE_FUNC (handle_reversepath) #endif #ifdef UPSTREAM_SUPPORT -static HANDLE_FUNC (handle_upstream) +static int _handle_upstream(struct config_s* conf, const char* line, + regmatch_t match[], proxy_type type) { char *ip; int port; @@ -1080,11 +1091,11 @@ static HANDLE_FUNC (handle_upstream) if (match[10].rm_so != -1) { domain = get_string_arg (line, &match[10]); if (domain) { - upstream_add (ip, port, domain, &conf->upstream_list); + upstream_add (ip, port, domain, type, &conf->upstream_list); safefree (domain); } } else { - upstream_add (ip, port, NULL, &conf->upstream_list); + upstream_add (ip, port, NULL, type, &conf->upstream_list); } safefree (ip); @@ -1092,6 +1103,21 @@ static HANDLE_FUNC (handle_upstream) return 0; } +static HANDLE_FUNC (handle_upstream) +{ + return _handle_upstream(conf, line, match, HTTP_TYPE); +} + +static HANDLE_FUNC (handle_upstream4) +{ + return _handle_upstream(conf, line, match, SOCKS4_TYPE); +} + +static HANDLE_FUNC (handle_upstream5) +{ + return _handle_upstream(conf, line, match, SOCKS5_TYPE); +} + static HANDLE_FUNC (handle_upstream_no) { char *domain; @@ -1100,7 +1126,7 @@ static HANDLE_FUNC (handle_upstream_no) if (!domain) return -1; - upstream_add (NULL, 0, domain, &conf->upstream_list); + upstream_add (NULL, 0, domain, HTTP_TYPE, &conf->upstream_list); safefree (domain); return 0; @@ -61,9 +61,11 @@ #ifdef UPSTREAM_SUPPORT # define UPSTREAM_CONFIGURED() (config.upstream_list != NULL) # define UPSTREAM_HOST(host) upstream_get(host, config.upstream_list) +# 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 /* @@ -853,10 +855,10 @@ process_client_headers (struct conn_s *connptr, hashmap_t hashofheaders) /* * 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; @@ -1265,6 +1267,88 @@ static void relay_connection (struct conn_s *connptr) return; } +static int +connect_to_upstream_proxy(struct conn_s *connptr, struct request_s *request) +{ + int len; + 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. */ @@ -1308,6 +1392,9 @@ connect_to_upstream (struct conn_s *connptr, struct request_s *request) 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.", @@ -1527,7 +1614,7 @@ void handle_connection (int fd) goto fail; } - if (!(connptr->connect_method && (connptr->upstream_proxy == NULL))) { + if (!connptr->connect_method || UPSTREAM_IS_HTTP(connptr)) { if (process_server_headers (connptr) < 0) { update_stats (STAT_BADCONN); goto fail; diff --git a/src/upstream.c b/src/upstream.c index 6b25f9b..91bf457 100644 --- a/src/upstream.c +++ b/src/upstream.c @@ -29,10 +29,22 @@ #include "log.h" #ifdef UPSTREAM_SUPPORT +const 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"; + } +} + /** * Construct an upstream struct from input data. */ -static struct upstream *upstream_build (const char *host, int port, const char *domain) +static struct upstream *upstream_build (const char *host, int port, const char *domain, + proxy_type type) { char *ptr; struct upstream *up; @@ -44,6 +56,7 @@ static struct upstream *upstream_build (const char *host, int port, const char * return NULL; } + up->type = type; up->host = up->domain = NULL; up->ip = up->mask = 0; @@ -57,8 +70,8 @@ static struct upstream *upstream_build (const char *host, int port, const char * 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, @@ -101,8 +114,8 @@ static struct upstream *upstream_build (const char *host, int port, const char * 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); } return up; @@ -119,11 +132,11 @@ fail: * Add an entry to the upstream list */ void upstream_add (const char *host, int port, const char *domain, - struct upstream **upstream_list) + proxy_type type, struct upstream **upstream_list) { struct upstream *up; - up = upstream_build (host, port, domain); + up = upstream_build (host, port, domain, type); if (up == NULL) { return; } @@ -202,8 +215,8 @@ struct upstream *upstream_get (char *host, struct upstream *up) up = NULL; if (up) - log_message (LOG_INFO, "Found upstream proxy %s:%d for %s", - up->host, up->port, host); + log_message (LOG_INFO, "Found upstream proxy %s %s:%d for %s", + proxy_type_name(up->type), up->host, up->port, host); else log_message (LOG_INFO, "No upstream proxy for %s", host); diff --git a/src/upstream.h b/src/upstream.h index 34dad68..7855214 100644 --- a/src/upstream.h +++ b/src/upstream.h @@ -31,17 +31,20 @@ * 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; }; #ifdef UPSTREAM_SUPPORT +const char *proxy_type_name(proxy_type type); extern void upstream_add (const char *host, int port, const char *domain, - struct upstream **upstream_list); + proxy_type type, struct upstream **upstream_list); extern struct upstream *upstream_get (char *host, struct upstream *up); extern void free_upstream_list (struct upstream *up); #endif /* UPSTREAM_SUPPORT */ |