Local transparent HTTP proxy

This article was originally written in March 2008.

Setting up Squid as a transparent HTTP proxy has been discussed plenty of times. All of these examples and blogs I’ve read on the subject assume that you run Squid on your network gateway. While this is a very common and sensible set up, it doesn’t suit my need. I need to lock down one single computer and perform filtering using Squid’s ACL mechanism, regardless of the network it’s plugged into.

Difference with Squid on gateway

The technique of running a local transparent HTTP proxy is basically the same as the usual proxying on the gateway. However, there is one more hurdle. If we indiscriminately redirect all outgoing HTTP requests via Squid, we create an infinite loop. After all, Squid itself has to perform HTTP requests too, which should not be looped through itself.

Unlooping the loop

The trick to prevent this infinite loop is to filter on user ID. We’ll tell IPTables that it should accept all HTTP requests coming from our Squid user, and redirect all others. Of course, this assumes that Squid runs as a user specifically reserved for this purpose.

Here is my IPTables configuration that takes care of this.

# Shortcuts
filter="ipttables -t filter"
nat="iptables -t nat"

# Proxy HTTP access through Squid
$nat -A OUTPUT -m owner --uid-owner 13 -j ACCEPT
$nat -A OUTPUT -p tcp --dport 80 -j REDIRECT -p tcp --to-port 3128

# Reject HTTPS
$filter -A OUTPUT -m owner --uid-owner 13 -j ACCEPT
$filter -A OUTPUT -p tcp --dport 443 -j REJECT

This set up assumes that Squid runs as the “proxy” user with uid 13. This is the default in Ubuntu and probably other distributions, but please check to ensure it matches your system.

The $nat rules tell IPTables to accept all HTTP connections coming from Squid, and to redirect all other HTTP connections to Squid.

The $filter rules are there to block HTTPS traffic. If I understand SSL connections well (and I believe I do) there is no way to transparently proxy those without breaking security. Since I want to prevent all HTTP access that doesn’t get routed through Squid, I simply block it. The user of the computer can set up her browser to use Squid for HTTPS connections.

Configuring Squid

The Squid part is no different than any other transparent proxying configuration. Just know that the redirected HTTP traffic will appear come from the same network interface as it was originally sent on. So if - without transparent proxy set up - your HTTP request would go through eth0, Squid will see a connection coming from the IP address of eth0. Use this knowledge to configure your ACLs.

Here is my configuration, just so you can take a look at how I configured things. This is for Squid 2.6, earlier versions used slightly different configuration for transparent proxying.

hierarchy_stoplist cgi-bin ?
acl QUERY urlpath_regex cgi-bin \?
no_cache deny QUERY

hosts_file /etc/hosts

acl all src 0.0.0.0/0.0.0.0
acl manager proto cache_object
acl localhost src 127.0.0.1/255.255.255.255
acl localhost src 172.27.0.4/255.255.255.255
acl to_localhost dst 127.0.0.0/8
acl SSL_ports port 443 563
acl SSL_ports port 873
acl lan src 172.27.0.0/24
acl Safe_ports port 80
acl Safe_ports port 21
acl Safe_ports port 443 563
acl Safe_ports port 70
acl Safe_ports port 210
acl Safe_ports port 1025-65535
acl Safe_ports port 280
acl Safe_ports port 488
acl Safe_ports port 591
acl Safe_ports port 777
acl Safe_ports port 631
acl Safe_ports port 873
acl Safe_ports port 901
acl purge method PURGE
acl CONNECT method CONNECT
http_access allow manager localhost
http_access deny manager
http_access allow purge localhost
http_access deny purge
http_access deny !Safe_ports
http_access deny CONNECT !SSL_ports
http_access deny to_localhost
http_access allow localhost
http_access deny all

http_reply_access allow all

# Transparent redirection options
always_direct allow all
http_port 0.0.0.0:3128 transparent

# Effective user/group
cache_effective_user proxy
cache_effective_group proxy

access_log /var/log/squid/access.log squid

icp_access allow all
cache_mgr sybren@stuvel.eu

forwarded_for off
coredump_dir /var/spool/squid

Most of this file is the bog-standard Squid configuration with all comments removed.

Conclusion

Hopefully this article explains how to secure and manage HTTP and HTTPS access on a single machine. It only handles connections to port 80, so HTTP servers listening on another port won’t be connected. Expand on the examples if you want, because the mechanism will be exactly the same for different ports.

If anything is unclear, don’t hesitate to contact me and ask for clarification.