Navigation Menu

Skip to content

gorgias/forwardingproxy

 
 

Repository files navigation

Build Status

Forwarding HTTP/S Proxy

A forwarding HTTP/S proxy. This server is useful when one wants to have originating requests to a destination service from a set of well-known IPs.

Usage

$ forwardingproxy -h
Usage of forwardingproxy:
  -addr string
    	Server address
  -avoid string
    	Site to be avoided
  -cert string
    	Filepath to certificate
  -clientreadtimeout duration
    	Client read timeout (default 5s)
  -clientwritetimeout duration
    	Client write timeout (default 5s)
  -destdialtimeout duration
    	Destination dial timeout (default 10s)
  -destreadtimeout duration
    	Destination read timeout (default 5s)
  -destwritetimeout duration
    	Destination write timeout (default 5s)
  -key string
    	Filepath to private key
  -lecachedir string
        Cache directory for certificates (default "/tmp")
  -letsencrypt
        Use letsencrypt for https
  -lewhitelist string
        Hostname to whitelist for letsencrypt
  -pass string
    	Server authentication password
  -serveridletimeout duration
    	Server idle timeout (default 30s)
  -serverreadheadertimeout duration
    	Server read header timeout (default 30s)
  -serverreadtimeout duration
    	Server read timeout (default 30s)
  -serverwritetimeout duration
    	Server write timeout (default 30s)
  -user string
    	Server authentication username
  -verbose
    	Set log level to DEBUG

To start the proxy as HTTP server, just run:

$ forwardingproxy

To start the proxy as HTTPS server, just provide server certificate and private key files:

$ forwardingproxy -cert cert.pem -key key.pem

To create a self-signed certificate and private key for testing, run:

$ openssl req -newkey rsa:2048 -nodes -keyout key.pem -new -x509 -sha256 -days 3650 -out cert.pem

Or enable letsencrypt

$ forwardingproxy -letsencrypt -lewhitelist proxy.somehostname.tld -lecachedir /home/somewhere/.forwardingproxycache

The server can be configured to run on a specific interface and port (-addr), be protected via PROXY-AUTHORIZATION (-user and -pass). Additionally, most timeouts can be customized.

To enable verbose logging output, use -verbose flag.

Implementation details

It is a simple HTTPS tunneling proxy that starts a Go HTTPS server at a given port awaiting CONNECT requests, basically dropping everything else. To start the HTTPS server one has to provide a server certificate and private key for the TLS handshake phase.

Once a client requests a CONNECT it will create a TCP connection to the provided destination host, and on successfully establishing this connection, hijack the original client connection, and transparently and bidirectionally copying incoming and outgoing TCP byte streams.

It has minimal logging using Uber's Zap logger.

Features

This is NIH (Not Invented Here syndrome), thus quality and feature set is not en-par with hosted or off-the-shelf solutions.

Compared to especially hosted solutions, insight into the proxies operations such as logging, monitoring, usage statistics need to be added if desired. Additionally, one has to setup the binary as a reliable server and automate deployments.

Background

If one has a third-party requirement to have server requests originating from a fixed IP address, there are mainly two options: (i) host code on a cloud provider such as an EC2 instance and connect the instance to an EIP (Elastic IP). (ii) But if code is hosted on a PaaS provider with no guarantee of a fixed IP, such as Heroku, one would proxy requests through a proxy server and have that proxy server attached to a fixed IP.

Proxy

To proxy HTTPS requests, one broadly has two options in software: Use the HTTP Tunnel feature via the CONNECT method, also called a Forwarding Proxy, or a Reverse Proxy. There are hardware solutions on OSI layer 3 instead of layer 7, namely a NAT proxy, but this is not discussed here as it more convenient nowadays to not require access to physical hardware or want to invest into a NAT proxy e.g. on AWS.

Forwarding Proxy

A forwarding proxy can come in two flavours:

One in which the proxy terminates an incoming client request, evaluates it, and forwards the request to a destination. This works for HTTP as well as for HTTPS. A subtle but important side-effect of using a forwarding proxy for HTTPS is that it would terminate the request, thus being able to inspect the request's content (and modify it).

The other in which the proxy uses tunneling via the CONNECT method. By this, a proxy accepts an initial CONNECT request entailing the entire URL as HOST value, rather than just the host address. The proxy then opens up a TCP connection to the destination and transparently forwards the raw communication from the client to the destination. This comes with the subtle difference that only the initial CONNECT request from the client to the proxy is terminated and can be analyzed, however, any further communication is not terminated nor intercepted thus SSL communication can't be read by the proxy.

One additional subtle thing to mention is that forwarding proxies using tunneling rely on clients to understand and comply to the HTTP tunneling RFC 2817 and thus have to be explicitly configured to use HTTP/S proxying, usually picking up the proxy url from environment variables such as HTTP_PROXY and HTTPS_PROXY respectively. For Go, see net/http/Transport and

Reverse Proxy

A reverse proxy accepts incoming requests from clients and routes them to a specific destination based on the request. Discriminators for destination could be the host, path, query parameters, any header even the body. A reverse proxy, in any case, intercepts and terminates the HTTP and HTTPS connections and creates new requests to the destinations.

Alternatives

One can consider alternatives in protocol and product, as well as Make vs Buy.

Alternatives to a forwarding proxy would be a reverse proxy or NAT proxy. Reverse proxies as outlined above would require more routing logic. A NAT proxy would require more network or hardware configuration even if it's abstracted by IaaS providers.

Alternative products would be Squid, NGINX, HAProxy, Varnish, TinyProxy, etc. NGINX is primarily meant to be used as a reverse proxy and can be difficult to set up acting as a forwarding proxy. HAProxy is similar to NGINX meant to be used as reverse proxy as well as HTTP cache. Varnish is primarily meant to be used as HTTP cache. Squid and TinyProxy are closest to be working as forwarding proxies, however it can be difficult to set them up on a new Amazon Linux 2 AMI EC2 instance, and TinyProxy is not maintained anymore since several years.

Alternatives to Make vs Buy would be:

Heroku's Private Spaces feature stable outbound IPs:

Stable outbound IPs

Securely connect apps to third party cloud services and corporate networks.

This would weight in with a price tag of either $1000 or $3000 respectively for GDPR compliance.

Another Make vs Buy alternative would be hosted Heroku's Add-ons that would offer stable IP support such as Fixie, Guru301, Proximo, QuotaGuard Static,

Fixie and Guru301 only support Heroku's United States region, not Europe. QuotaGuard Static and Proximo both support Heroku's Europe region and would offer 20,000 respectively 50,000 requests per month for $19 respectively $25 per month.

License

MIT License.

About

A HTTP/S forwarding proxy in Go

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • Go 88.8%
  • Makefile 8.6%
  • Dockerfile 2.6%