An http/https proxy for navigating through rough air. This proxy is not full-featured. It doesn't support authentication, whitelisting or custom headers. It's small, transparent, and does as little as possible. Be sure to read through the code, it should take you less than 5 minutes.
To build from source you can do:
$ go get github.com/film42/turbulence
$ ./bin/turbulence
Or you can grab the pre-built docker container with default options:
$ docker run -p 25000:25000 -d film42/turbulence:latest
Or use your own config:
$ docker run -p 26000:26000 -d -v $(pwd)/test:/config film42/turbulence:latest --config config/config.json
Usage of ./turbulence:
-config string
config file
-dial-timeout int
timeout for connecting to an upstream server in seconds (default 30)
-password string
password for proxy authentication
-port int
listen port (default 25000)
-strip-proxy-headers
strip proxy headers from http requests (default true)
-use-incoming-local-addr
attempt to use the local address of the incoming connection when connecting upstream (default true)
-username string
username for proxy authentication
Turbulence supports basic authentication. Other massive proxies like Squid support complex authentication, whitelisting and custom headers, but Turbulence doesn't try to solve these other problems. It's built to do as little as possible. If you need authentication or the ability to modify headers, then you should use a different proxy, but if whitelisting is good enough, use iptables
instead. Even if you use Squid's whitelisting, the proxy is still publicly accessible and will respond to proxy connections with an unauthorized error. If you're using a cloud provider like amazon or google, be sure to use their firewall tools.
If you want to use a sample config instead of passing your options as command line arguments, you may do so. Here's an example config:
{
"port": 9000,
"strip_proxy_headers": true,
"use_incoming_local_addr": true,
"dial_timeout": 30,
"credentials": [
{
"username": "ron.swanson",
"password": "g0ld5topsTheGovt"
}
]
}
Save and run:
./turbulence --config config_for_ron.json
After using large proxies like Squid, I realized I was only using a very small subset of its features and when something would go wrong, I wasn't sure what why. After a few hours of trying to solve those problems, I looked up the proxy server RFC and realized how easy it would be to start from scratch and only add the most basic components required to proxy http and https requests. After first writing a functional proxy in ruby with nio4r, I realized go would be a much easier runtime to work with. Turbulence is the result of a few iterations of writing a toy proxy. Turbulence isn't nearly as battle tested as Squid, but it is very tiny and can fit into your head. I've hit Turbulence with pings and full proxy requests continuously for over two weeks (still running) and the memory utilization has been about 1/3 of Squid, but YMMV.
Turbulence is a transparent http/https proxy, meaning it let's you proxy your http/https traffic without modifying any of the original request. This doesn't necessarily mean that Turbulence is anonymous. If your client sets an X-Forwarded-For
header or any other request header that could hint the request is being proxied, it will be sent to the server. If you want your requests to look like they're not proxied, be sure that your client does not set any additional headers. While http requests can be modified by Turbulence without raising any red flags, it's not possible to modify https requests without man-in-the-middling your connection, which is detectable by any client that pins their certificate. For this reason, Turbulence does not manipulation http/https request and only proxies bytes between two tcp connections.
HTTP Request
When a client connects to the proxy using HTTP, the HTTP request will look like a regular HTTP request except for the first line which will contain the full host of the destination server:
GET https://server.example.com/articles HTTP/1.1
...
Turbulence connects to the host server.example.com:80
and writes the http request without https://server.example.com
prefixed to the request path. After this, Turbulence copies bytes between tcp connections until one of them hangs up. This allows Turbulence to support http keepalive for both http and https mode.
Try using curl to watch the request flow:
$ curl -v -x 0.0.0.0:25000 http://httpbin.org/headers http://httpbin.org/headers
HTTPS Request
When a client connects to the proxy using HTTPS, the client sends a CONNECT
request to change the connection into socket mode for a TLS handshake.
CONNECT server.example.com:443 HTTP/1.1
...
Turbulence opens a tcp connection to server.example.com:443
and responds to the client with a 200 Connection established
response to say everything is 👌. At this point, Turbulence copies bytes between the client and server until one of them hangs up. This allows Turbulence to supports http keepalive.
Try using curl to watch the request flow:
$ curl -v -x 0.0.0.0:25000 https://httpbin.org/headers https://httpbin.org/headers
To make an example proxied https connection with ruby's Net::HTTP
, do the following:
require "net/http"
uri = URI.parse("https://httpbin.org/headers")
proxy = Net::HTTP::Proxy("0.0.0.0", 25000)
client = proxy.start(uri.host, :use_ssl => true)
response = client.get(uri.request_uri)
puts response.body
Which will return the following:
{
"headers": {
"Accept": "*/*",
"Accept-Encoding": "gzip;q=1.0,deflate;q=0.6,identity;q=0.3",
"Host": "httpbin.org",
"User-Agent": "Ruby"
}
}