Transparent proxing

Usually in corporate environment, or e.g in case of bigger schools., network administrators use application level proxies. A proxy can make internet access much faster as well as safer, however, these effects are getting more insignificant while secure connections are emerging. On the other hand, endpoint's proxy configuration not always trivial in a heterogeneous software environment. In some rare cases dealing with proxy configurations may became very time consuming while the existing of the proxy is absolutely a must have (the reason why is not important here).

If we are operating this heterogeneous software environment, we do not want to deal with configuration of maven, Docker, internet browsers, Linux network installers and so on, especially when some service can be reached only bypassed the proxy.

For example, while Docker base images only through the proxy can be pulled from the Docker's hub, the recently built image can be pushed to local repository only without proxy.

Than, what we can do to make our life more comfortable? We can use configuration management tools, like Puppet and Ansible, or we can send our proxy into the background, in that sense, we can make our proxies transparent with iptables at the router. I choose the second one because it is possible without any additional configuration changes at the endpoints.

Before we go into the detaileds, I want to show how the network looks like in a nutshell. In the below picture we want to hide proxy for the two desktop machines used by the gateway host. The last one is a RedHat 6.4 server with strict iptables firewall rules and a lot of other marginal service like dnsmasq. OS on client hosts, behind the gateway, doesn't matter until the default gateway setting is correct on them.

network diagram

Now let's take a deep dive into the question: how to hide that undesirable proxy?

The key of the solution is redsocks with iptables.

Redsocks is a tool which allows you to redirect any TCP connection to a SOCKS or an HTTP(S) proxy. Since it can be used with iptables, this is a system-wide solution which can be extended to whole subnet as well if we set it up on the appropriate router (here, this router is the gateway host).

I started from source code and built an own binary from scratch but you don't have to do this, you may also install it from repository.

After we defined our proxies in the redsocks.conf file and started redsocks service, redsocks will listen and wait TCP connections redirected by iptables. To start and maintain redsocks, I just simply used supervisord.

In my case proxy is located on the 10.100.100.100 IP address, SOCKS is on port 1080/tcp, HTTP and HTTPS on 8080/tcp so my redsocks.conf looks like this:

base {
daemon = on;
//log = stderr;
redirector = iptables;
}

redsocks {
local_ip = 0.0.0.0;
local_port = 12345;
ip = 10.100.100.100;
port = 1080;
type = socks5;
}

redsocks {
local_ip = 0.0.0.0;
local_port = 12346;
ip = 10.100.100.100;
port = 8080;
type = http-relay;
}

redsocks {
local_ip = 0.0.0.0;
local_port = 12347;
ip = 10.100.100.100;
port = 8080;
type = http-connect;
}

At this point, we have a service which can handle TCP streams and redirect to the appropriate kind of proxy based on the port number (e.g., 12345 means SOCKS proxy). Nothing magic, right?

The little magic starting here: we have to create some iptables rules to catch network connections, and if it is going towards the public internet redirect them to our recently started redsoks service and finally to the appropriate proxy service.

There are several special addresses that shouldn't be handled by the proxy. First, we have to create exceptions for them, otherwise we won't be able to reach the proxy itself. A new firewall chain, REDSOCKS, will help to separate proxy related rules inside of iptables.

# Create new chain
iptables -t nat -N REDSOCKS

# Ignore LANs and some other reserved addresses
iptables -t nat -A REDSOCKS -d 0.0.0.0/8 -j RETURN
iptables -t nat -A REDSOCKS -d 10.0.0.0/8 -j RETURN
iptables -t nat -A REDSOCKS -d 127.0.0.0/8 -j RETURN
iptables -t nat -A REDSOCKS -d 169.254.0.0/16 -j RETURN
iptables -t nat -A REDSOCKS -d 172.16.0.0/12 -j RETURN
iptables -t nat -A REDSOCKS -d 192.168.0.0/16 -j RETURN
iptables -t nat -A REDSOCKS -d 224.0.0.0/4 -j RETURN
iptables -t nat -A REDSOCKS -d 240.0.0.0/4 -j RETURN

With the following rules iptables can distinguish the traffic type and choose the right proxy. HTTP traffic comes on 80/tcp port and is redirected to the gateway's 12346 port, secure HTTP comes on 443/tcp and is redirected to the 12347 port, and all others to the 12345 port, which actually means the SOCKS proxy. SOCKS proxy is not an application aware proxy as HTTP(S), it can only allow or refuse connections without any further inspection like virus scanning and caching. This is the reason why, for example, SSH connections will be possible.

# All other TCP connections must be redirected to redsocks ports
iptables -t nat -A REDSOCKS -p tcp -m tcp --dport 443 -j REDIRECT --to-ports 12347
iptables -t nat -A REDSOCKS -p tcp -m tcp --dport 80 -j REDIRECT --to-ports 12346
iptables -t nat -A REDSOCKS -p tcp -m tcp -j REDIRECT --to-ports 12345

However, in the above network diagram I didn't mentioned (sorry :) ) I have an OpenVPN service as well, so the following two rules will handle not just the endpoints' traffic but the VPN's too.

# if it cames in on em2 or tun0 (internal network or VPN), and it is TCP, send it to REDSOCKS
iptables -t nat -A PREROUTING -i em2 -p tcp -j REDSOCKS
iptables -t nat -A PREROUTING -i tun0 -p tcp -j REDSOCKS

In general it is useful to handle connections initiated on the gateway in a same way:

# if it is locally originated it also send to REDSOCKS
iptables -t nat -A OUTPUT -p tcp -j REDSOCKS

That's all. We have successfully hidden our corporate proxy, at least while we use only TCP connections. Other protocols will be discussed in an other post.

Just a side note: it is absolutely correct that tracapath shows something different then you expect at first.

Címkék