iptables+tproxy+squid透明代理需满足内核支持(config_ip_nf_target_tproxy_ipv4)、prerouting链规则、路由打标、squid intercept端口、客户端网关/dns正确配置及acl精准控制,缺一不可。

iptables + Squid 是最直接、最可控的组合,但必须满足内核支持和流量路径两个硬条件。不满足就白配。
确认内核是否支持透明代理
Linux 2.6.28+ 内核默认启用 IP: transparent proxy support,但某些精简版或云镜像(如部分 Alpine 或 CoreOS)会裁掉。运行以下命令检查:
zcat /proc/config.gz | grep CONFIG_IP_NF_TARGET_TPROXY_IPV4
或查看模块是否存在:
lsmod | grep tproxy
如果无输出,说明内核没编译该功能,iptables -t mangle -j TPROXY 会报错 No chain/target/match by that name。此时不能硬上 Squid 透明模式,得换方案(比如用 cproxy + TPROXY 用户态转发,或退回到 REDIRECT 模式——但会丢失原始目的 IP,Squid 日志里看不到真实访问域名)。
iptables 规则必须打在 PREROUTING 链,且用 TPROXY 不是 REDIRECT
很多人卡在这一步:用 REDIRECT 转发到 Squid 的 3128 端口,结果 Squid 日志全是 127.0.0.1,无法做基于域名的策略。真正透明的关键是保留原始目标地址,靠 TPROXY 实现:
iptables -t mangle -A PREROUTING -i enp1s0 -p tcp --dport 80 -j TPROXY --tproxy-mark 0x1/0x1 --on-port 3128- 必须配合路由表打标:
ip rule add fwmark 0x1 lookup 100,再加ip route add local 0.0.0.0/0 dev lo table 100 -
Squid配置里必须写http_port 3128 intercept(不是transparent,那是旧版关键字),且监听0.0.0.0:3128,不能只绑127.0.0.1
漏掉任意一条,流量就进不了 Squid 的 intercept 模式,或者被内核丢弃。
客户端网关和 DNS 必须指向透明网关,且不能绕过
透明代理不是“插上就能用”,它依赖网络层路径控制:
- 客户端默认网关必须设为透明网关的内网 IP(比如
192.168.1.1),否则流量根本不经过它 - DNS 必须由客户端自己解析(不能让 Squid 代查),所以 DNS 服务器要设成公网 DNS(如
8.8.8.8),不能设成网关本身——除非你额外部署了 DNS 转发服务(如dnsmasq)并确保它不干扰 TPROXY 流量 - 若客户端是 Windows,需确认它没启用“快速启动”或“混合关机”,这类机制会导致 ARP 缓存残留,改完网关后仍走旧路径
别忽略 Squid 的 acl 和 http_access 控制粒度
很多人以为配通 intercept 就万事大吉,结果发现所有流量都放行或全被拦截。Squid 的透明模式下,http_access 规则依然生效,但匹配依据是原始请求头里的 Host 字段(不是 URL),所以:
- 拒绝百度但放行谷歌?写
acl badsite dstdomain .baidu.com,不是.baidu.com后面少个点 - 想按用户分流?透明模式下没有认证上下文,
ident_lookup基本不可靠,得结合源 IP 段或 TLS SNI(需开启ssl_bump) - 日志格式要用
%rm %ru %rp %un %ui,其中%ru才是原始请求 URI,%rm是方法,%rp是原始端口——这些才是调试依据
真正难的从来不是“怎么配”,而是“为什么这条规则没生效”。抓包看三次握手是否到 Squid、查 /var/log/squid/cache.log 是否有 intercept 相关错误、确认 iptables -t mangle -vnL PREROUTING 计数器是否递增——这些比抄命令重要得多。











