Proxying software which is not proxy aware

Yesterday I came up against a problem I didn’t immediately have an answer to, something that doesn’t happen all that often. Today I found an answer and I thought I’d share it.

Imagine a network like this:

Internal_Net <-> Internal_Firewall <-> DMZ <-> External_Firewall <-> Internet

The internal network and firewall have no route to the internet. The DMZ and external firewall do. Internal hosts can access internet resources via a Squid proxy in the DMZ, but what happens when you have software which is not proxy aware, an IMAP client for example.

In a normal routed situation, you would make an exception for this kind of traffic and allow it directly through the firewall. But in this case we can’t do that, the internal firewall is not directly connected to the external firewall and cannot forward the traffic on.

We can’t NAT the traffic directly to the squid proxy because IMAP does not provide destination information within the data stream (as HTTP does) so the proxy would have no way to know where to connect to externally.

Another possibility is an IMAP proxy, using NAT again. However existing IMAP proxies assume you want to proxy to a single IMAP server, or a predefined list. This was not the case for us, this client needed to be able to connect to any server provided by a user.

What we needed was a way to make a connection to the Squid proxy, make a CONNECT request with the original destination information and then pass the data stream to it.

What to do?

The answer, as it turns out, is “RedSocks”. This little app (which is apt-get'able on Debian) listens for connections from clients and forwards them to a proxy. It’s party trick is this; you use an iptables REDIRECT to alter redirect the traffic from its original external destination to the local RedSocks port. When a new client connects, RedSocks looks in the kernel NAT tracking table and finds the original destination information (which has been lost from the IP packets that it sees by this point) and uses it to issue a CONNECT request to the proxy. It then forwards the data stream and as far as the client is concerned, it’s directly connected to the server it thought it was connecting to.

The detail:

The following is installed on the internal firewall (192.168.0.254). It intercepts the outbound traffic (in this case TCP port 993) and redirects it to RedSocks which is installed locally and listening on port 12345.

Redsocks in turn connects to the DMZ proxy at 192.168.1.10:3128

/etc/redsocks.conf:

base {
        log_debug = off;
        log_info = on;
        log = “syslog:daemon”;
        daemon = on;
        user = redsocks;
        group = redsocks;
        redirector = iptables;
}

redsocks {
        /* `local_ip’ defaults to 127.0.0.1 for security reasons,
         * use 0.0.0.0 if you want to listen on every interface.
         * `local_*’ are used as port to redirect to.
         */
        local_ip = 192.168.0.254;
        local_port = 12345;
        // `ip’ and `port’ are IP and tcp-port of proxy-server
        // You can also use hostname instead of IP, only one (random)
        // address of multihomed host will be used.
        ip = 192.168.1.10;
        port = 3128;
        // known types: socks4, socks5, http-connect, http-relay
        type = http-connect;
        // login = “foobar”;
        // password = “baz”;
}

IPTables config:

iptables -A PREROUTING -t nat -i internal -p tcp –dport 993 -j REDIRECT –to 12345

If you have INPUT rules restricting access to the firewall itself, make sure you allow connections to RedSocks:

iptables -A INPUT -i internal -d 192.168.0.254 -p tcp –dport 12345 -j ACCEPT

And finally, on the squid proxy, make sure you have an ACL to allow the outbound connections

acl internal src 192.168.0.0/24
acl proxy_ports port 993
acl CONNECT method CONNECT
http_access allow internal proxy_ports CONNECT

Sorted!