
在路由器的转发路径上,UA2F 把经过它的 HTTP 请求里的 User-Agent 字段统一改写,让内网里不同设备(手机、电脑、电视盒子)看起来像同一台设备发出的流量。它针对的是"基于 User-Agent 的设备指纹识别"——当网络侧用 UA 判断"这是不是违规共享、是不是多设备"时,把 UA 抹平就是最直接的反识别手段。
关键不在于"改什么",而在于"怎么改":UA2F 不碰应用层代理、不解密 HTTPS,而是借助 **NFQUEUE 机制**,在报文还停在防火墙队列里、尚未被转发出去时拦下来改掉,再放回去。理解 NFQUEUE,就理解了 UA2F 的全部原理。
netfilter(iptables/nftables 的内核引擎)里有一类 target 叫 NFQUEUE。它的作用是:把匹配到的数据包从内核态交给用户态程序处理,处理完再由程序决定丢弃、放行还是修改后重新入队。
UA2F 依赖的正是这条通道。防火墙规则命中目标包后,不立即走正常转发,而是扔进一个编号队列(queue-num,常见 10010);UA2F 通过 libnetfilter_queue 取包、改包、再 verdict 回去。两个细节决定了它为什么"稳":
--queue-bypass 兜底:如果用户态程序挂了、没来取包,带 bypass 的队列会让包直接按原路径放行,而不是全部卡死——最多不改写,不会把整网掐断。UA2F 自动安装的 netfilter 规则(mangle 表)大致长这样(简化示意):
iptables -t mangle -N ua2f iptables -t mangle -A ua2f -d 10.0.0.0/8 -j RETURN # 不处理保留地址 iptables -t mangle -A ua2f -d 127.0.0.0/8 -j RETURN iptables -t mangle -A ua2f -d 192.168.0.0/16 -j RETURN iptables -t mangle -A ua2f -p tcp --dport 443 -j RETURN # 不处理 HTTPS iptables -t mangle -A ua2f -p tcp --dport 22 -j RETURN # 不处理 SSH iptables -t mangle -A ua2f -p tcp --dport 80 -j NFQUEUE --queue-num 10010 iptables -t mangle -A FORWARD -p tcp -j ua2f
逻辑非常克制:先排除保留地址、排除 443/22 这类不该动的流量,只对目标端口 80 的 TCP 包进 NFQUEUE。这就是"只拦 80 端口"的由来。
因为 User-Agent 只在明文 HTTP 里看得到,而 80 端口承载的正是未加密的 HTTP。
80 = HTTP = 明文请求行、各种头部(含 UA)都是明文,UA2F 能直接读、直接改。这是一个"能改的才改、改不了的放过去"的边界决策,也决定了 UA2F 的能力上限:它只在 HTTP 世界里有效。如今网站普遍强制 HTTPS,这也是它被视作"早期方案"的原因(见第八节)。
全篇最有信息量的问题,答案分两层:改得动和改够用。
TCP 三次握手之后,客户端第一个携带数据的 TCP 报文,通常就包含了完整的 HTTP 请求起始行和头部。因为请求行 + 请求头(含 UA)整体不大,而一个 TCP 段约能装 MSS(默认 1460 字节)数据,正常情况下它们都落在同一个首包里。所以 UA2F 判断一个包是不是 HTTP 请求,方法很朴素:看它是否以 HTTP 方法开头(GET、POST 等)。是,就解析头部找 UA;不是,直接放走。
User-Agent 是客户端在请求头里主动声明的字段,整个会话只有请求方有,服务端响应里没有。只要把客户端第一个请求里的 UA 改掉,这一整条连接的服务端视角就已经被"骗"过去了——不需要、也没法改响应方向。
一句话记忆点:UA 在首包、改首包就够;等量替换让首包改完"天衣无缝",无需追踪整条连接——长度不变,TCP 序号和校验和都不必重算,服务端回的 ACK 依然对得上。User-Agent:。NFQUEUE 每包都有内核↔用户态开销,所以 UA2F 用连接跟踪进一步减少进队列的包:
nohttp:把"非 HTTP 目标 IP:端口"临时记进 ipset(带超时),同目标后续连接直接 RETURN,连首包判定都省。disable_connmark 开关:关闭后降低性能,但能避免和别的也改 Connmark 的程序冲突。这些优化都指向同一件事:能不进 NFQUEUE 的包,一个都别进。
| 模式 | 机制 | 适用 | 注意 |
|---|---|---|---|
| NFQUEUE(默认) | netfilter 队列直接改写 TCP 包本体 | 保留原有行为,最通用 | 在转发路径上直接改包 |
| REDIRECT | 透明代理,流量引到本地端口,UA2F 再连原目标 | 处理本机 OUTPUT 流量 | 需要本地监听端口 |
| TPROXY | 透明代理,适合接管转发流量 | 转发流量接管 | 需策略路由把 fwmark 指向 lo;不动本机 OUTPUT |
一个易踩的坑:TPROXY 固定监听端口的透明代理不处理本机自己的 OUTPUT 流量,本机流量得用 REDIRECT 或 NFQUEUE;同时 UA2F 自己出站连接会打 SO_MARK,防火墙规则要 bypass 这个 mark,否则改写后的连接又被同一套规则抓回,形成回环。
iptables-mod-nfqueue、libnetfilter-queue 等custom_ua 长度与原 UA 接近(等量替换避免序号/校验和异常)--queue-bypass 时不会。程序不取包,包就按原路径直接放行,最多不改写,不会掐断网络。这是"宁可失效也不雪崩"的兜底。
-->