Local transparent HTTP proxy
Setting up Squid as a
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
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.
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
$nat rules tell IPTables to accept all HTTP
connections coming from Squid, and to redirect all other HTTP
connections to Squid.
$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.
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
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
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
access_log /var/log/squid/access.log squid
icp_access allow all
Most of this file is the bog-standard Squid configuration with
all comments removed.
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.