<html>
<head>
<meta content="text/html; charset=ISO-8859-1"
http-equiv="Content-Type">
</head>
<body bgcolor="#FFFFFF" text="#000000">
<div class="moz-cite-prefix">So I invested some time in this today,
and came up with this patch that implements SOCKS5 support. Can
anyone suggest improvements?<br>
<br>
Sample config :<br>
<br>
upstream backend {<br>
server 127.0.0.1:9050 socks=ip4.me;<br>
}<br>
<br>
server {<br>
listen 1234;<br>
server_name localhost;<br>
<br>
location / {<br>
proxy_pass <a class="moz-txt-link-freetext" href="http://backend">http://backend</a>;<br>
proxy_connect_timeout 5s;<br>
<br>
proxy_set_header Host ip4.me;<br>
}<br>
}<br>
<br>
No DNS lookups are done at nginx, which is proper behavior.<br>
<br>
<br>
<br>
Index: src/http/ngx_http_upstream_round_robin.c<br>
===================================================================<br>
--- src/http/ngx_http_upstream_round_robin.c (revision 5017)<br>
+++ src/http/ngx_http_upstream_round_robin.c (working copy)<br>
@@ -87,6 +87,12 @@<br>
peers->peer[n].weight = server[i].weight;<br>
peers->peer[n].effective_weight =
server[i].weight;<br>
peers->peer[n].current_weight = 0;<br>
+<br>
+#if (NGX_HTTP_UPSTREAM_SOCKS)<br>
+ peers->peer[n].socks = server[i].socks;<br>
+ peers->peer[n].socks_port =
server[i].socks_port;<br>
+ peers->peer[n].socks_hostname =
server[i].socks_hostname;<br>
+#endif<br>
n++;<br>
}<br>
}<br>
@@ -145,6 +151,12 @@<br>
backup->peer[n].max_fails =
server[i].max_fails;<br>
backup->peer[n].fail_timeout =
server[i].fail_timeout;<br>
backup->peer[n].down = server[i].down;<br>
+<br>
+#if (NGX_HTTP_UPSTREAM_SOCKS)<br>
+ backup->peer[n].socks = server[i].socks;<br>
+ backup->peer[n].socks_port =
server[i].socks_port;<br>
+ backup->peer[n].socks_hostname =
server[i].socks_hostname;<br>
+#endif<br>
n++;<br>
}<br>
}<br>
@@ -453,6 +465,12 @@<br>
pc->socklen = peer->socklen;<br>
pc->name = &peer->name;<br>
<br>
+#if (NGX_HTTP_UPSTREAM_SOCKS)<br>
+ pc->socks = peer->socks;<br>
+ pc->socks_port = peer->socks_port;<br>
+ pc->socks_hostname = peer->socks_hostname;<br>
+#endif<br>
+<br>
/* ngx_unlock_mutex(rrp->peers->mutex); */<br>
<br>
if (pc->tries == 1 && rrp->peers->next) {<br>
Index: src/http/ngx_http_upstream.c<br>
===================================================================<br>
--- src/http/ngx_http_upstream.c (revision 5017)<br>
+++ src/http/ngx_http_upstream.c (working copy)<br>
@@ -146,7 +146,12 @@<br>
static void ngx_http_upstream_ssl_handshake(ngx_connection_t *c);<br>
#endif<br>
<br>
+#if (NGX_HTTP_UPSTREAM_SOCKS)<br>
+void ngx_upstream_socks_init_handshake(ngx_http_request_t *,<br>
+ ngx_http_upstream_t *);<br>
+#endif<br>
<br>
+<br>
ngx_http_upstream_header_t ngx_http_upstream_headers_in[] = {<br>
<br>
{ ngx_string("Status"),<br>
@@ -1228,6 +1233,15 @@<br>
<br>
u->request_sent = 0;<br>
<br>
+#if (NGX_HTTP_UPSTREAM_SOCKS)<br>
+<br>
+ if (u->peer.socks) {<br>
+ ngx_upstream_socks_init_handshake(r, u);<br>
+ return;<br>
+ }<br>
+<br>
+#endif<br>
+<br>
if (rc == NGX_AGAIN) {<br>
ngx_add_timer(c->write,
u->conf->connect_timeout);<br>
return;<br>
@@ -4131,7 +4145,8 @@<br>
|NGX_HTTP_UPSTREAM_MAX_FAILS<br>
|NGX_HTTP_UPSTREAM_FAIL_TIMEOUT<br>
|NGX_HTTP_UPSTREAM_DOWN<br>
-
|NGX_HTTP_UPSTREAM_BACKUP);<br>
+
|NGX_HTTP_UPSTREAM_BACKUP<br>
+
|NGX_HTTP_UPSTREAM_SOCKS_FLAG);<br>
if (uscf == NULL) {<br>
return NGX_CONF_ERROR;<br>
}<br>
@@ -4334,6 +4349,29 @@<br>
continue;<br>
}<br>
<br>
+#if (NGX_HTTP_UPSTREAM_SOCKS)<br>
+ if (ngx_strncmp(value[i].data, "socks=", 6) == 0) {<br>
+<br>
+ if (!(uscf->flags &
NGX_HTTP_UPSTREAM_SOCKS_FLAG)) {<br>
+ goto invalid;<br>
+ }<br>
+<br>
+ if (us->socks) {<br>
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,<br>
+ "duplicate socks proxy");<br>
+<br>
+ goto invalid;<br>
+ }<br>
+<br>
+ us->socks = 1;<br>
+ us->socks_port = 80;<br>
+ us->socks_hostname.len = value[i].len - 6;<br>
+ us->socks_hostname.data = value[i].data + 6;<br>
+<br>
+ continue;<br>
+ }<br>
+#endif<br>
+<br>
goto invalid;<br>
}<br>
<br>
Index: src/http/ngx_http_upstream.h<br>
===================================================================<br>
--- src/http/ngx_http_upstream.h (revision 5017)<br>
+++ src/http/ngx_http_upstream.h (working copy)<br>
@@ -93,6 +93,12 @@<br>
<br>
unsigned down:1;<br>
unsigned backup:1;<br>
+<br>
+#if (NGX_HTTP_UPSTREAM_SOCKS)<br>
+ unsigned socks:1;<br>
+ in_port_t socks_port;<br>
+ ngx_str_t socks_hostname;<br>
+#endif<br>
} ngx_http_upstream_server_t;<br>
<br>
<br>
@@ -102,6 +108,7 @@<br>
#define NGX_HTTP_UPSTREAM_FAIL_TIMEOUT 0x0008<br>
#define NGX_HTTP_UPSTREAM_DOWN 0x0010<br>
#define NGX_HTTP_UPSTREAM_BACKUP 0x0020<br>
+#define NGX_HTTP_UPSTREAM_SOCKS_FLAG 0x0040<br>
<br>
<br>
struct ngx_http_upstream_srv_conf_s {<br>
@@ -332,6 +339,11 @@<br>
<br>
unsigned request_sent:1;<br>
unsigned header_sent:1;<br>
+<br>
+#if (NGX_HTTP_UPSTREAM_SOCKS)<br>
+ ngx_http_upstream_handler_pt next_read_event_handler;<br>
+ ngx_http_upstream_handler_pt next_write_event_handler;<br>
+#endif<br>
};<br>
<br>
<br>
Index: src/http/ngx_http_upstream_round_robin.h<br>
===================================================================<br>
--- src/http/ngx_http_upstream_round_robin.h (revision 5017)<br>
+++ src/http/ngx_http_upstream_round_robin.h (working copy)<br>
@@ -35,6 +35,12 @@<br>
#if (NGX_HTTP_SSL)<br>
ngx_ssl_session_t *ssl_session; /* local to a
process */<br>
#endif<br>
+<br>
+#if (NGX_HTTP_UPSTREAM_SOCKS)<br>
+ unsigned socks:1;<br>
+ in_port_t socks_port;<br>
+ ngx_str_t socks_hostname;<br>
+#endif<br>
} ngx_http_upstream_rr_peer_t;<br>
<br>
<br>
Index: src/http/modules/ngx_http_upstream_socks_module.c<br>
===================================================================<br>
--- src/http/modules/ngx_http_upstream_socks_module.c (revision
0)<br>
+++ src/http/modules/ngx_http_upstream_socks_module.c (revision
0)<br>
@@ -0,0 +1,133 @@<br>
+<br>
+#include <ngx_config.h><br>
+#include <ngx_core.h><br>
+#include <ngx_http.h><br>
+<br>
+static void ngx_upstream_socks_write_handler(ngx_http_request_t
*r,<br>
+ ngx_http_upstream_t *u);<br>
+static void ngx_upstream_socks_read_handler(ngx_http_request_t
*r,<br>
+ ngx_http_upstream_t *u);<br>
+<br>
+void<br>
+ngx_upstream_socks_init_handshake(ngx_http_request_t *r,<br>
+ ngx_http_upstream_t *u)<br>
+{<br>
+ ngx_connection_t *c;<br>
+<br>
+ c = u->peer.connection;<br>
+<br>
+ u->next_write_event_handler = u->write_event_handler;<br>
+ u->next_read_event_handler = u->read_event_handler;<br>
+<br>
+ u->write_event_handler = ngx_upstream_socks_write_handler;<br>
+ u->read_event_handler = ngx_upstream_socks_read_handler;<br>
+}<br>
+<br>
+static void<br>
+ngx_upstream_socks_write_handler(ngx_http_request_t *r,<br>
+ ngx_http_upstream_t *u)<br>
+{<br>
+ ngx_connection_t *c;<br>
+<br>
+ c = u->peer.connection;<br>
+<br>
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log,
0,<br>
+ "http socks upstream handshake handler");<br>
+<br>
+ if (c->write->timedout) {<br>
+ ngx_http_finalize_request(r, NGX_HTTP_GATEWAY_TIME_OUT);<br>
+ return;<br>
+ }<br>
+<br>
+ if (!u->peer.socks_handshake1_sent) {<br>
+ u->peer.socks_handshake1_sent = 1;<br>
+<br>
+ // TODO, this is ugly<br>
+ u_char handshake[] = {0x05, 0x01, 0x00};<br>
+ c->send(c, handshake, 3);<br>
+<br>
+ } else if (u->peer.socks_handshake2_recv &&
!u->peer.socks_handshake3_sent) {<br>
+ u_char *handshake;<br>
+ ngx_uint_t len;<br>
+<br>
+ len = 7 + u->peer.socks_hostname.len;<br>
+<br>
+ handshake = ngx_pnalloc(r->pool, len);<br>
+<br>
+ handshake[0] = 5; // version<br>
+ handshake[1] = 1; // connect<br>
+ handshake[2] = 0;<br>
+ handshake[3] = 3; // specify dns<br>
+ handshake[4] = (u_char)u->peer.socks_hostname.len;<br>
+<br>
+ // port<br>
+ *(u_short*)(handshake+len-2) =
ntohs(u->peer.socks_port);<br>
+<br>
+ ngx_memcpy(handshake+5, u->peer.socks_hostname.data,
u->peer.socks_hostname.len);<br>
+<br>
+ c->send(c, handshake, len);<br>
+<br>
+ ngx_pfree(r->pool, handshake);<br>
+<br>
+ u->peer.socks_handshake3_sent = 1;<br>
+ }<br>
+}<br>
+<br>
+static void<br>
+ngx_upstream_socks_read_handler(ngx_http_request_t *r,<br>
+ ngx_http_upstream_t *u)<br>
+{<br>
+ ngx_connection_t *c;<br>
+<br>
+ c = u->peer.connection;<br>
+<br>
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log,
0,<br>
+ "http socks upstream handshake recv handler");<br>
+<br>
+ if (c->read->timedout) {<br>
+ ngx_http_finalize_request(r, NGX_HTTP_GATEWAY_TIME_OUT);<br>
+ return;<br>
+ }<br>
+<br>
+ if (!u->peer.socks_handshake2_recv) {<br>
+ u_char buf[2];<br>
+<br>
+ u->peer.socks_handshake2_recv = 1;<br>
+ c->recv(c, buf, 2);<br>
+<br>
+ if (buf[0] != 5 || buf[1] != 0) {<br>
+ ngx_http_finalize_request(r, NGX_HTTP_BAD_GATEWAY);<br>
+ return;<br>
+ }<br>
+<br>
+ } else if (u->peer.socks_handshake3_sent &&
!u->peer.socks_handshake4_recv) {<br>
+ u_char buf[22];<br>
+<br>
+ c->recv(c, buf, 5);<br>
+<br>
+ if (buf[0] != 5 || buf[1] != 0 || buf[2] != 0) {<br>
+ ngx_http_finalize_request(r, NGX_HTTP_BAD_GATEWAY);<br>
+ return;<br>
+ }<br>
+<br>
+ if (buf[3] == 1) {<br>
+ c->recv(c, buf+5, 5);<br>
+<br>
+ } else if (buf[3] == 4) {<br>
+ c->recv(c, buf+5, 17);<br>
+ <br>
+ } else if (buf[3] == 3) {<br>
+ u_char *hostname_and_port = ngx_pnalloc(r->pool,
((size_t)buf[4]) + 2);<br>
+ c->recv(c, hostname_and_port, ((size_t)buf[4]) +
2);<br>
+ ngx_pfree(r->pool, hostname_and_port);<br>
+ }<br>
+<br>
+ u->peer.socks_handshake4_recv = 1;<br>
+<br>
+ // restore previous handlers<br>
+ u->write_event_handler =
u->next_write_event_handler;<br>
+ u->read_event_handler = u->next_read_event_handler;<br>
+<br>
+ u->write_event_handler(r, u);<br>
+ }<br>
+}<br>
Index: src/event/ngx_event_connect.h<br>
===================================================================<br>
--- src/event/ngx_event_connect.h (revision 5017)<br>
+++ src/event/ngx_event_connect.h (working copy)<br>
@@ -52,6 +52,16 @@<br>
ngx_event_save_peer_session_pt save_session;<br>
#endif<br>
<br>
+#if (NGX_HTTP_UPSTREAM_SOCKS)<br>
+ unsigned socks:1;<br>
+ unsigned socks_handshake1_sent:1;<br>
+ unsigned socks_handshake2_recv:1;<br>
+ unsigned socks_handshake3_sent:1;<br>
+ unsigned socks_handshake4_recv:1;<br>
+ in_port_t socks_port;<br>
+ ngx_str_t socks_hostname;<br>
+#endif<br>
+<br>
#if (NGX_THREADS)<br>
ngx_atomic_t *lock;<br>
#endif<br>
Index: auto/options<br>
===================================================================<br>
--- auto/options (revision 5017)<br>
+++ auto/options (working copy)<br>
@@ -99,6 +99,7 @@<br>
HTTP_UPSTREAM_IP_HASH=YES<br>
HTTP_UPSTREAM_LEAST_CONN=YES<br>
HTTP_UPSTREAM_KEEPALIVE=YES<br>
+HTTP_UPSTREAM_SOCKS=NO<br>
<br>
# STUB<br>
HTTP_STUB_STATUS=NO<br>
@@ -216,6 +217,8 @@<br>
--with-http_random_index_module)
HTTP_RANDOM_INDEX=YES ;;<br>
--with-http_secure_link_module)
HTTP_SECURE_LINK=YES ;;<br>
--with-http_degradation_module)
HTTP_DEGRADATION=YES ;;<br>
+ --with-http_upstream_socks_module)<br>
+
HTTP_UPSTREAM_SOCKS=YES ;;<br>
<br>
--without-http_charset_module)
HTTP_CHARSET=NO ;;<br>
--without-http_gzip_module)
HTTP_GZIP=NO ;;<br>
@@ -364,6 +367,7 @@<br>
--with-http_secure_link_module enable
ngx_http_secure_link_module<br>
--with-http_degradation_module enable
ngx_http_degradation_module<br>
--with-http_stub_status_module enable
ngx_http_stub_status_module<br>
+ --with-http_upstream_socks_module enable SOCKS5 support for
upstreams<br>
<br>
--without-http_charset_module disable
ngx_http_charset_module<br>
--without-http_gzip_module disable ngx_http_gzip_module<br>
Index: auto/modules<br>
===================================================================<br>
--- auto/modules (revision 5017)<br>
+++ auto/modules (working copy)<br>
@@ -365,6 +365,11 @@<br>
HTTP_SRCS="$HTTP_SRCS $HTTP_UPSTREAM_KEEPALIVE_SRCS"<br>
fi<br>
<br>
+if [ $HTTP_UPSTREAM_SOCKS = YES ]; then<br>
+ have=NGX_HTTP_UPSTREAM_SOCKS . auto/have<br>
+ HTTP_SRCS="$HTTP_SRCS
src/http/modules/ngx_http_upstream_socks_module.c"<br>
+fi<br>
+<br>
if [ $HTTP_STUB_STATUS = YES ]; then<br>
have=NGX_STAT_STUB . auto/have<br>
HTTP_MODULES="$HTTP_MODULES ngx_http_stub_status_module"<br>
<br>
<br>
<br>
<br>
Tom<br>
<br>
<br>
Op 1/25/13 1:13 PM, Tom van der Woerdt schreef:<br>
</div>
<blockquote cite="mid:510276F7.3020809@tvdw.eu" type="cite">Yes, I
currently use a proxy like that, but it feels like a performance
killer to do it like that. If implemented in nginx it could be so
much faster.
<br>
<br>
About SOCKS implementations: as long as authentication isn't
required, the handshake is really, really easy, especially version
4. The lack of a framing protocol makes it behave like any normal
socket once the handshake is done.
<br>
<br>
Tom
<br>
<br>
<br>
Op 1/25/13 12:57 PM, Aleksandar Lazic schreef:
<br>
<blockquote type="cite">Hi,
<br>
<br>
There are some http2socks proxy out there.
<br>
<br>
<a class="moz-txt-link-freetext" href="http://www.privoxy.org/">http://www.privoxy.org/</a>
<br>
<a class="moz-txt-link-freetext" href="http://www.privoxy.org/user-manual/config.html#SOCKS">http://www.privoxy.org/user-manual/config.html#SOCKS</a>
<br>
<br>
<a class="moz-txt-link-freetext" href="http://www.delegate.org/delegate/">http://www.delegate.org/delegate/</a>
<br>
<a class="moz-txt-link-freetext" href="http://www.delegate.org/delegate/Manual.htm#SOCKS">http://www.delegate.org/delegate/Manual.htm#SOCKS</a>
<br>
<br>
<a class="moz-txt-link-freetext" href="http://en.wikipedia.org/wiki/SOCKS#Translating_proxies">http://en.wikipedia.org/wiki/SOCKS#Translating_proxies</a>
<br>
<br>
The setup coul looks like
<br>
<br>
client -> nginx -> http-proxylistener ->
socks-proxyrequester -> socks-server
<br>
<br>
OT: Sock5 is not so easy if you want to implement the full
protocol, imho.
<br>
<br>
I Agree with you that this would be a nice upsteam module, even
that I don't
<br>
need it at the moment.
<br>
<br>
Cheers
<br>
Aleks
<br>
Am 23-01-2013 17:05, schrieb Tom van der Woerdt:
<br>
<blockquote type="cite">Hi,
<br>
<br>
A project I'm working on has a backend server that, for
security
<br>
reasons, can only be accessed via a SOCKS4a/SOCKS5 proxy. A
frontend
<br>
server for this project (nginx) has one simple task: to proxy
all
<br>
incoming connections to the backend server.
<br>
<br>
Right now, nginx cannot do this, because it has no support for
<br>
proxying upstream connections via a SOCKS proxy. The current
temporary
<br>
workaround is to run another service on the frontend machine
that acts
<br>
like a HTTP server but proxies the data to the backend -
basically
<br>
everything I'd like nginx to do. I cannot use this service as
my main
<br>
frontend, because there are a few other files that also need
to be
<br>
served.
<br>
<br>
SOCKS4a and SOCKS5 are really easy protocols and are basically
just
<br>
sockets but with an alternate handshake (skip the DNS lookup,
send the
<br>
hostname to the socket instead). Since they should be so easy
to
<br>
implement, I'm requesting that on this mailing list.
<br>
<br>
I was thinking of a config file that would look something like
this :
<br>
<br>
upstream backend {
<br>
server hidden_dns.local socks4=127.0.0.1:1234;
<br>
}
<br>
<br>
server {
<br>
location / {
<br>
proxy_pass <a class="moz-txt-link-freetext" href="http://backend">http://backend</a>;
<br>
}
<br>
}
<br>
<br>
As far as I'm aware, this feature wouldn't break anything,
since a
<br>
SOCKS connections behaves just like any other normal socket.
<br>
<br>
Thanks for considering,
<br>
Tom van der Woerdt
<br>
<br>
<br>
_______________________________________________
<br>
nginx-devel mailing list
<br>
<a class="moz-txt-link-abbreviated" href="mailto:nginx-devel@nginx.org">nginx-devel@nginx.org</a>
<br>
<a class="moz-txt-link-freetext" href="http://mailman.nginx.org/mailman/listinfo/nginx-devel">http://mailman.nginx.org/mailman/listinfo/nginx-devel</a>
<br>
</blockquote>
<br>
_______________________________________________
<br>
nginx-devel mailing list
<br>
<a class="moz-txt-link-abbreviated" href="mailto:nginx-devel@nginx.org">nginx-devel@nginx.org</a>
<br>
<a class="moz-txt-link-freetext" href="http://mailman.nginx.org/mailman/listinfo/nginx-devel">http://mailman.nginx.org/mailman/listinfo/nginx-devel</a>
<br>
</blockquote>
<br>
<br>
<br>
<fieldset class="mimeAttachmentHeader"></fieldset>
<br>
<pre wrap="">_______________________________________________
nginx-devel mailing list
<a class="moz-txt-link-abbreviated" href="mailto:nginx-devel@nginx.org">nginx-devel@nginx.org</a>
<a class="moz-txt-link-freetext" href="http://mailman.nginx.org/mailman/listinfo/nginx-devel">http://mailman.nginx.org/mailman/listinfo/nginx-devel</a></pre>
</blockquote>
<br>
</body>
</html>