summaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGonzalo Tornaria <tornaria@math.utexas.edu>2016-12-20 21:30:43 +0000
committerrofl0r <rofl0r@users.noreply.github.com>2018-02-06 16:11:39 +0000
commit8906b0734e5c61016d9d4090507f010b2006292d (patch)
tree73eea974f5a292516e1ffd85ed44ddeae1b34764 /src
parent116e59e93346ddbe08f56f8c7e8bd648690c0242 (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.c34
-rw-r--r--src/reqs.c93
-rw-r--r--src/upstream.c31
-rw-r--r--src/upstream.h5
4 files changed, 146 insertions, 17 deletions
diff --git a/src/conf.c b/src/conf.c
index d568dfb..ca46930 100644
--- a/src/conf.c
+++ b/src/conf.c
@@ -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;
diff --git a/src/reqs.c b/src/reqs.c
index 990152a..a3d8162 100644
--- a/src/reqs.c
+++ b/src/reqs.c
@@ -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 */