System-wide proxy manager

Manage a pool of proxies to be used globally or explicitly for certain applications. Arbitrary traffic can be tunneled via multiple upstream endpoints.

Many applications provide SOCKS or HTTP proxy support, which however often lacks advanced features and management options. proxyd acts as a local proxy itself and delegates incoming connections to configured upstream proxies, while providing additional functionality.

As open proxies are usually not very reliable, proxyd can for example detect when one goes down and will skip it in the next attempt. Additionally, there is the possibility of proxy chaining, where each proxy is used to connect to the next one, until the actual destination is reached – whether this is needed or desired due to pseudo-privacy concerns. For applications without built-in proxy support or when system-wide tunnelling is intended, proxyd can transparently intercept any traffic that is redirected to it via a single, simple firewall rule.

Mode of operation

Depending on the chosen configuration, there are several possible modes for client-side and proxy pooling behaviour.

Accepting new connections

Provided a particular port, proxyd will always listen on it for new incoming connections on localhost only. Per default, these connections are assumed to be SOCKS4.

Additionally, this port will be accepting transparently redirected connections, which can be of arbitrary type. As those connections already indicate their intended destination, there is no need for a particular tunnel protocol (such as SOCKS4) to be configured in the client application. For example, when running on port 4444, any HTTPS traffic can be intercepted by:

iptables -t nat -A OUTPUT -p tcp --dport 443 -m mark --mark 0 -j REDIRECT --to-ports 4444

In order to prevent loops, outgoing connections will be marked in transparent mode. Without the match on the non-existing mark above, proxyd would be doomed to connect to itself over and over again.

In case a particular usecase requires using TPROXY instead of the REDIRECT target, support for this is amongst the #defineable flags.

Establishing a proxy chain

By default, proxyd will take a list of proxies and pass incoming connections through all of them, in the given order.

+-----------+                                                         
|  Client   |     +---------+          +---------+     +-------------+
+-v-SOCKS-v-+     | Proxy_1 | --...--> | Proxy_N | --> | Destination |
| localhost | --> +---------+    ^     +---------+     +-------------+
+-----------+  ^                 |                                    
               |_ CONNECT/SOCKS _|                                    

After retrieving the original destination from the client connection, each proxy is used to connect to the next one, until the target gets reached eventually. Currently, supported methods for upstream connections are HTTP CONNECT (alias "SSL") and SOCKS4. In order to increase fault tolerance when connecting, proxyd can skip steps and retry upon error. This is done to the extent of the configured minimum number of proxies to use, which can even be 0, allowing for a direct connection as fallback.

For a brief discussion on why this mode might be questionable with security in mind, please see below.

Maintaining a proxy pool

In pool mode, the proxy ordering is arbitrary, as the given number of proxies gets selected randomly for each new connection. If one step of the chain fails, it will be replaced with a spare one if available, and the upstream connection starts from scratch.

The most obvious scenario for this feature is to randomly choose a single proxy from a list until a connection can be successfully established – without notice of the client application.

Proxy manager usage

Start proxyd by at least providing the port to locally listen on:

./proxyd --port=N [--min=N|--pool=N] [--proxies=<filename>] [proxy1 [proxy2 ...]]

Support for dropping privileges and global status tracking via shared memory IPC requires the -lcap and -lrt linker flags, respectively. Both are optional and can be disabled in the Makefile, though.

port
This localhost port will accept direct SOCKS4 connections or transparently redirected ones without any protocol used.
min
Lower limit on the number of used proxies to be traversed in the default (chaining) mode. Apparently defunct proxies can thus be skipped until this value is reached. Per default, all given proxies have to be used. A value of 0 allows direct connections.
pool
Switches to pool mode, with the given number of proxies being selected randomly for each connection.
proxies
Use this file as proxy list, one per line. Proxies to be used can be defined in the form of proto://ip:port. Currently supported protocols are socks4 and http.
proxy list
Like entries in the proxy list file, but as arguments.

Note that when running as root, the support for transparently redirected connections will be enabled – in this case a local firewall rule as mentioned before can be used. In addition or otherwise, 127.0.0.1:port will accept SOCKS4 requests from applications configured to do so.

Open proxy security considerations

Hopping from proxy to proxy intuitively seems to improve security in general. However, while this might help to obscure ones origin from non-savvy parties, constraints such as confidentiality or integrity actually are at higher risk.

Each traversed proxy has to be regarded as untrustworthy and multiple hops increase the chance of an intermediary, malicious one. As there is no additional end-to-end security layer, each node can take part in observing or manipulating proxied traffic. Apart from sniffing, the approaches for tracking or deanonymization range from injecting simple scripts, actual exploits, to statistical timing analysis and traffic profiling.

In short, the more involved untrusted parties, the more the number of places where traffic could be eavesdropped, correlated, or tampered with. This additional caveat should be taken into consideration when the risks and advantages of using open proxies are evaluated for each usecase – more is not always better.

Code & Download