How traffic is diverted without client configuration, what interception breaks (TLS, HSTS, pinning, IP auth), how to detect it, and TPROXY vs REDIRECT.
Transparent and intercepting are not synonyms: RFC 2616 defines a transparent proxy as one that does not modify messages, while RFC 3040 defines interception as traffic diverted without client configuration.
Interception is structurally incompatible with 407 proxy authentication, because the client does not believe it is talking to a proxy.
REDIRECT gives you the original destination via SO_ORIGINAL_DST; TPROXY additionally lets the proxy keep the client's source address on the upstream connection.
Squid logs SECURITY ALERT: Host header forgery detected when an intercepted request's Host does not match the intercepted destination IP.
An intercepting proxy receives traffic the client never intended to send to a proxy, because the network diverted it. The client emits an ordinary origin-form request (GET /page HTTP/1.1 with a Host header) aimed at the origin's IP address, and a router, firewall or inline appliance steers those packets to a proxy instead. The proxy must then reconstruct the intended destination from the Host header and the original destination address, because nothing in the request tells it that a proxy is involved.
That reconstruction is the source of essentially every problem in this article.
The vocabulary is genuinely muddled, and the confusion costs people hours.
Term
Where it is defined
What it means there
Transparent proxy
RFC 2616 section 1.3
A proxy that does not modify the request or response beyond what proxy authentication and identification require. The opposite is a non-transparent proxy, which rewrites content.
Interception proxy
RFC 3040
A proxy that receives traffic diverted by the network, without the client having been configured to use it.
"Transparent proxy" in vendor and operator usage
Everywhere else
Usually means the RFC 3040 sense: the client is unaware.
So a proxy can be intercepting and non-transparent (it diverts your traffic and injects headers), or explicit and transparent (you configured it and it passes messages through untouched). Squid's own configuration reflects the split: the http_port option is spelled intercept, not transparent, precisely because the older name was ambiguous. Older Squid releases used transparent as a synonym; modern configuration should use intercept.
When you read "transparent proxy" in a runbook, resolve which sense is meant before acting on it.
Return routing must come back through the proxy host
Inline bump-in-the-wire
2
Yes
Depends on the appliance's mode
A bridge or tap physically in the path
Fail-open/fail-closed decisions; a fault takes the link down
DNS interception
7 (DNS)
No, the destination IP is the proxy's
Proxy's IP
Control of the resolver or port 53
Broken by DoH/DoT and by hardcoded resolvers; TLS name mismatch
Default-gateway or ARP manipulation
2/3
Yes
Proxy's IP
Being the gateway
Coarse, all-or-nothing per subnet
DNS interception deserves a specific caution: it changes what a name resolves to, so the client opens TLS to an address that cannot present a valid certificate for that name unless you intercept TLS as well. It is also the mechanism most thoroughly defeated by modern clients, since DNS-over-HTTPS bypasses the local resolver entirely.
REDIRECT is a DNAT target that rewrites the destination to a local address and port. The proxy accepts a normal socket, and recovers what the client originally asked for with a getsockopt(SO_ORIGINAL_DST) call:
bash
# Divert forwarded HTTP to a proxy listening on 3129
iptables -t nat -A PREROUTING -i eth1 -p tcp --dport 80 -j REDIRECT --to-port 3129
text
http_port 3129 intercept
The upstream connection is then made from the proxy's own address, so the origin sees the proxy.
TPROXY is different: it does not rewrite anything. It marks the packet and delivers it to a socket bound with the IP_TRANSPARENT option while the addressing stays intact, so the accepting socket already knows the original destination, and the proxy can also bind its outgoing socket to the client's address. The result is an origin that sees the real client IP.
bash
# Divert to a TPROXY-capable proxy, preserving both addresses
iptables -t mangle -N DIVERT
iptables -t mangle -A DIVERT -j MARK --set-mark 1
iptables -t mangle -A DIVERT -j ACCEPT
# Established flows already owned by a local socket go straight to it
iptables -t mangle -A PREROUTING -p tcp -m socket -j DIVERT
# New flows to port 80 are handed to the proxy on 3129
iptables -t mangle -A PREROUTING -p tcp --dport 80 \
-j TPROXY --tproxy-mark 0x1/0x1 --on-port 3129
# Marked packets must be delivered locally, not routed onward
ip rule add fwmark 1 lookup 100
ip route add local default dev lo table 100
text
http_port 3129 tproxy
The -m socket -j DIVERT rule is the part people omit. Without it, packets belonging to an already-established intercepted connection are re-evaluated by the routing table, do not match a local socket by ordinary rules, and get forwarded away from the proxy; the symptom is that connections establish and then stall after the first exchange.
TLS on port 443. Redirecting 443 to a proxy that only relays gives you SNI-level visibility at best. Anything more requires generating a certificate per site from a private CA, which means TLS interception with a corporate root CA and installing that root in every client's trust store.
Certificate pinning. Applications that pin a public key or a specific CA reject the forged certificate and fail hard, usually with an opaque network error rather than a TLS message. Android has made this the default rather than the exception: apps targeting API level 24 and above trust only system CAs unless their network security configuration explicitly opts into user-installed CAs, so an enterprise root added by a user profile is ignored by most apps.
HSTS. RFC 6797 removes the click-through: a browser holding an HSTS entry, or seeing a preloaded domain, refuses to let the user accept an untrusted certificate at all. There is no user-facing workaround, only trust-store distribution.
Non-HTTP traffic on port 80. Interception rules select by port, not by protocol. Anything that speaks a custom protocol on 80 to traverse firewalls hits an HTTP parser and dies. The symptom is a connection that establishes and then closes immediately, or an HTTP error page delivered into a binary protocol stream.
IP-based authentication at the origin. A REDIRECT-based deployment replaces the client IP with the proxy's, so partner allow-lists keyed on office addresses break for everyone or, worse, start letting through traffic from any client behind the proxy. TPROXY avoids this; X-Forwarded-For does not help, because the origin is a third party that does not trust your headers. See the X-Forwarded-For header for why third-party origins ignore it.
QUIC and HTTP/3. Interception rules written for TCP do not see UDP 443 at all, so browsers that negotiate HTTP/3 silently bypass the proxy. The usual response is to block UDP/443 outbound and force fallback to TCP, which is worth planning for rather than discovering. See HTTP/2 and HTTP/3 through proxies.
Proxy authentication. This one is structural and not fixable: 407 Proxy Authentication Required and Proxy-Authorization only work when the client knows it is speaking to a proxy. An intercepted client believes it is talking to the origin, so a 407 is nonsense to it. Intercepting deployments must identify users by source IP, by an agent on the device, or by redirecting to a captive portal that sets a cookie. This is the strongest single argument for explicit configuration; see proxy authentication.
Squid treats the two as different ports with different parsing rules, and refuses to mix them.
Behaviour
http_port 3128 (explicit)
http_port 3129 intercept
Expected request-target
Absolute-form (GET http://host/ ...) or CONNECT
Origin-form (GET / ...) with Host
Destination determination
From the request-target
From SO_ORIGINAL_DST, cross-checked against Host
Proxy auth (407)
Supported
Not possible
CONNECT
Supported
Not applicable, there is no CONNECT from an unaware client
Client awareness
Yes
No
Typical error on a mismatched request
Works
Invalid Request / ERR_INVALID_REQ
The cross-check is the interesting part. Because a keep-alive connection is intercepted once but can carry requests for many hostnames, a client could open a connection to an innocuous IP and then send Host: internal.example.com on it, aiming the proxy at a destination the network policy never approved. Squid detects the mismatch and logs it in cache.log:
text
SECURITY ALERT: Host header forgery detected on local=93.184.216.34:80
remote=10.0.3.17:51422 FD 14 flags=33 (local IP does not match any domain IP)
SECURITY ALERT: By user agent: curl/8.5.0
SECURITY ALERT: on URL: internal.example.com/
The immediate cause is often benign: DNS round-robin or a CDN handed the client one address while Squid's own resolution returned a different one for the same name, and the addresses legitimately differ. The fix is to make the proxy and the clients use the same resolver and respect the same TTLs, not to disable the check. The host_verify_strict directive controls how strictly this is applied to non-intercepted traffic; intercepted traffic is always verified, because without it interception is an open door into any destination reachable from the proxy. That overlaps directly with SSRF and the proxy layer.
A second gotcha: the proxy's own outbound traffic must be excluded from the redirect rules or it loops back in. On a gateway host, exempt by source and by owner:
Use a captive-portal probe endpoint.http://connectivitycheck.gstatic.com/generate_204 returns 204 with an empty body when unmolested. Any other status, any body, or a redirect means something answered on the origin's behalf.
Compare the certificate issuer against the public chain. If the issuer is an internal CA name, TLS is being intercepted.bash
Check whether the connection survives a bogus Host. Connect by IP with a Host for a domain that resolves elsewhere. A direct origin ignores the mismatch or serves its default site; an intercepting proxy frequently returns its own error page, and Squid logs the forgery alert shown above.
Compare DNS answers.dig +short example.com @1.1.1.1 against the system resolver. Divergence points at DNS interception rather than packet redirection.
Send a non-HTTP payload to port 80.printf 'PING\r\n' | nc example.com 80 should produce the origin's own behaviour; an HTTP 400 or an HTML error page means an HTTP parser is in the path.
Connections establish then stall after a few kilobytes, TPROXY deployment. Missing -m socket -j DIVERT rule, or the fwmark routing rule is absent, so established-flow packets are routed onward instead of delivered locally.
ERR_INVALID_REQ from Squid on an intercept port. A proxy-aware client sent an absolute-form request to an intercept port. Give explicit clients a separate http_port and exclude their source addresses from the redirect rules.
Certificate warnings everywhere except on managed laptops. The private root reached the OS trust store but not containers or runtimes with their own bundles (Python certifi, Node's built-in roots, Java cacerts), each of which needs the CA added separately. See corporate proxies and developer tooling.
A specific mobile app fails while the browser works. Certificate pinning, or an Android app targeting API 24+ that ignores user-installed CAs. There is no proxy-side fix; exempt the destination from bumping.
Sporadic Host header forgery alerts for one busy CDN-hosted domain. DNS answers differ between client and proxy. Align resolvers and honour TTLs.
Proxy CPU climbs and traffic loops. Proxy egress is being re-intercepted. Exclude the proxy's own source address and UID from the redirect chain.
Long-lived streams die at a fixed interval. The proxy imposed its own idle timeout on a connection the client believed was direct. Server-sent events and WebSockets are the usual casualties; see proxy buffering and streaming responses.
What is the difference between a transparent proxy and an intercepting proxy?#
Strictly, "transparent" is RFC 2616 terminology for a proxy that does not modify messages, and "intercepting" is RFC 3040 terminology for a proxy that receives traffic diverted by the network without client configuration. In everyday operator usage "transparent proxy" almost always means the intercepting sense. Squid uses intercept as the configuration keyword to avoid the ambiguity.
Not without terminating TLS. Redirecting port 443 to a proxy gives it the ClientHello, so it can see the SNI hostname, ALPN and TLS version, and it can allow or block on those. Reading URLs, headers or bodies requires generating certificates from a CA the client trusts, and that fails against pinned applications and does not work at all for HSTS-protected sites when the CA is missing.
Does an intercepting proxy preserve the client IP?#
Only with TPROXY or an equivalent transparent-source mechanism, where the proxy binds its upstream socket to the client's address using IP_TRANSPARENT. With REDIRECT, WCCP without TPROXY, or DNS-based diversion, the origin sees the proxy's address. Adding X-Forwarded-For does not help when the origin is a third party, since it has no reason to trust your headers.
Why does proxy authentication not work in intercept mode?#
Because 407 Proxy Authentication Required is a message from a proxy to a client that knows it is using one. An intercepted client thinks it is talking to the origin server, so a 407 is an unexpected status from the wrong party and the client will not send Proxy-Authorization. Intercepting deployments identify users by IP, by a device agent, or by a captive portal instead.
How do I tell whether my traffic is being intercepted right now?#
Check three things: whether plaintext HTTP responses carry Via or X-Cache headers, whether a known probe endpoint such as http://connectivitycheck.gstatic.com/generate_204 still returns an empty 204, and whether the TLS certificate for a well-known site is issued by a public CA or by an internal one. Any deviation on those three covers the common deployments.
Is interception better or worse than an explicit proxy?#
Explicit configuration is better wherever you can achieve it: it supports proxy authentication, gives clients a defined no_proxy escape hatch, produces clearer errors, and does not require you to own the routing path. Interception is the fallback for unmanaged devices and appliances that cannot be configured. A common compromise is explicit configuration via PAC or WPAD for managed clients, plus interception as a backstop for everything else, which is discussed in PAC files and WPAD.
Every normative claim on this page is checked against the specification or the vendor documentation listed here. Where behaviour is version dependent, the version is named in the text.
Found something wrong, or behaviour that differs on your version?Report it with the version number and a primary source. Anything substantive is fixed in the page and logged on the corrections page. See editorial standards for how pages are researched, sourced and reviewed.