Interception (transparent) proxying with Squid
Interception (often called transparent proxying) sends web traffic to Squid without configuring any browser: the router or firewall quietly redirects port 80 to the proxy. It works for plain HTTP, breaks some things you may not expect, and does not work for HTTPS unless you decrypt traffic, which raises serious legal and ethical questions. A proxy auto-config file is often the better choice.
How interception works
With a normal (explicit) proxy, the browser knows it is talking to Squid and sends full URLs. With interception, the client thinks it is talking straight to the web server. A firewall rule changes the packet’s path so it lands on a special Squid port instead. Squid then works out where the client meant to go and fetches the page on its behalf.
The Squid wiki is blunt about the costs:
- No proxy authentication. The browser does not know a proxy exists, so it will not send proxy credentials. Squid disables authentication on intercept and tproxy ports.
- Path MTU problems. Interception can break path MTU discovery, which can make some sites unreachable, especially over PPPoE links with a reduced MTU.
- Double DNS lookups. The client resolves the name, then Squid resolves it again.
- Confusing errors. When a site is down, users see a Squid error page or a hung browser, not the error they would normally get.
The wiki also says to test in a non-live environment before you switch it on for users.
intercept versus tproxy
intercept | tproxy | |
|---|---|---|
| Mechanism | NAT (REDIRECT or DNAT) | Linux TPROXY, BSD divert-to |
| Address servers see | The proxy’s address | The client’s own address |
| IPv6 | IPv4 only on older kernels | IPv4 and IPv6 |
| Where it runs | NAT rules must be on the Squid machine | Squid box with policy routing |
Use intercept for a simple setup where Squid sits in the traffic path. Use tproxy when servers or logs downstream must see real client addresses. Either way, keep an ordinary forward-proxy port as well; the Squid examples always pair them.
NAT interception (REDIRECT)
This is the Squid wiki’s REDIRECT example, for a Squid box at 192.168.0.2 that is also the gateway. In squid.conf:
http_port 3128
http_port 3129 intercept
Then the firewall rules (iptables):
SQUIDIP=192.168.0.2
SQUIDPORT=3129
iptables -t nat -A PREROUTING -s $SQUIDIP -p tcp --dport 80 -j ACCEPT
iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port $SQUIDPORT
iptables -t nat -A POSTROUTING -j MASQUERADE
iptables -t mangle -A PREROUTING -p tcp --dport $SQUIDPORT -j DROP
Line by line: Squid’s own outgoing requests are left alone (without this rule you get a forwarding loop); every other port-80 connection is redirected to port 3129; outgoing traffic is masqueraded; and direct connections to port 3129 from outside are dropped, because the mangle table runs before NAT. If the router and Squid are different machines, the wiki says to use policy routing to deliver packets to the Squid box, and do the NAT there.
The Squid wiki gives iptables rules only. The same REDIRECT setup written for nftables, using the syntax in the nft manual, looks like this:
table ip nat {
chain prerouting {
type nat hook prerouting priority dstnat; policy accept;
ip saddr 192.168.0.2 tcp dport 80 accept
tcp dport 80 redirect to :3129
}
chain postrouting {
type nat hook postrouting priority srcnat; policy accept;
masquerade
}
}
table inet filter {
chain prerouting {
type filter hook prerouting priority mangle; policy accept;
tcp dport 3129 drop
}
}
Save it as a file and load it with nft -f. Test it on a lab machine first; on a live gateway, a mistake in the NAT table cuts everyone off.
TPROXY interception
TPROXY keeps the client’s address on outgoing connections. Squid must be built with --enable-linux-netfilter (distribution packages normally are), and the port must be dedicated to tproxy:
http_port 3128
http_port 3129 tproxy
The wiki’s packet-marking and routing rules:
iptables -t mangle -N DIVERT
iptables -t mangle -A DIVERT -j MARK --set-mark 1
iptables -t mangle -A DIVERT -j ACCEPT
iptables -t mangle -A PREROUTING -p tcp -m socket -j DIVERT
iptables -t mangle -A PREROUTING -p tcp --dport 80 -j TPROXY --tproxy-mark 0x1/0x1 --on-port 3129
ip -f inet rule add fwmark 1 lookup 100
ip -f inet route add local default dev eth0 table 100
The DIVERT rule must come before the TPROXY rule. You also need IP forwarding on and reverse-path filtering off (net.ipv4.ip_forward = 1, net.ipv4.conf.all.rp_filter = 0 and the same for the interface). For IPv6, repeat the rules with ip6tables and ip -f inet6.
Why HTTPS is different
An HTTPS connection is encrypted from the browser to the server, and the server proves its identity with a certificate. A proxy in the middle cannot read the request, so redirecting port 443 to a normal intercept port does not work.
Squid’s SSL-Bump feature can read the TLS handshake and decide what to do in steps. In the first steps it can peek at the server name the client asked for (SNI) without changing anything, then splice (pass the connection through untouched) or bump (decrypt and re-encrypt). The least intrusive setup only peeks and splices, which lets you log or filter by host name without decrypting anything:
ssl_bump peek all
ssl_bump splice all
This still needs an https_port with intercept ssl-bump and a certificate (tls-cert=), and a Squid built with OpenSSL (on Debian, the squid-openssl package). Bumping goes further: Squid generates a fake certificate for each site, signed by your own certificate authority, which must be installed as trusted on every client. Apps that pin their certificates will refuse to connect at all.
Legal and ethical limits. Decrypting other people’s HTTPS exposes passwords, banking, health and private messages. Intercepting communications without authority or consent is a crime in many countries; in the United States, for example, the federal Wiretap Act (18 U.S.C. § 2511) bans intentional interception, with narrow exceptions such as consent and a service provider protecting its own service. If you plan it for a workplace, get a written policy, tell users, take legal advice first, and splice (do not decrypt) sensitive categories such as banking and health. If you are not sure you are allowed to, do not do it.
Alternatives: PAC files and WPAD
Often you do not need interception at all. A proxy auto-config (PAC) file is a small JavaScript function the browser runs for every request to choose a proxy:
function FindProxyForURL(url, host) {
if (isPlainHostName(host) || dnsDomainIs(host, ".example.lan")) {
return "DIRECT";
}
return "PROXY proxy.example.lan:3128; DIRECT";
}
Serve it with the MIME type application/x-ns-proxy-autoconfig. The browser then uses Squid as an explicit proxy, so authentication works, HTTPS goes through CONNECT normally and nothing breaks when the proxy is down (the ; DIRECT fallback).
WPAD (Web Proxy Auto-Discovery) lets browsers find the PAC file on their own, through DHCP option 252 or a DNS name such as wpad.example.lan, fetching /wpad.dat. It never became a standard: the IETF draft expired in 1999. Any machine that manages to answer to the name “wpad” can steer browsers through itself, so make sure only your own server can claim that name, or set the PAC address directly through group policy or device management.
Sources
- Interception caching FAQ, Squid wiki
- Linux traffic interception using REDIRECT, Squid wiki
- Linux traffic interception using DNAT, Squid wiki
- TPROXY version 4, Squid wiki
- SslBump peek and splice, Squid wiki
- http_port directive, Squid configuration reference
- https_port directive, Squid configuration reference
- squid-openssl package, Debian
- nft(8) manual page, Debian
- Performing network address translation, nftables wiki
- Proxy Auto-Configuration (PAC) file, MDN
- Web Proxy Auto-Discovery Protocol (expired draft), IETF
- 18 U.S.C. § 2511, Legal Information Institute, Cornell Law School