iptables无法直接匹配tcp窗口大小,因其tcp模块不支持该字段,string模块不扫描头部,u32模块受分片和选项长度影响极不稳定;可靠防御应基于连接状态、速率限制(如limit/recent模块)及高层工具(suricata、ebpf)。

iptables 本身不支持直接匹配 TCP 窗口大小(TCP Window Size)这一字段。
这是关键前提——TCP 窗口大小位于 TCP 头部的第 14–15 字节(共 2 字节,网络字节序),而 iptables 的内置匹配模块(如 tcp、string、u32)中:
-
tcp模块仅支持匹配源/目的端口、TCP 标志位(SYN/ACK/FIN等)、序列号(--tcp-option仅限选项字段,非窗口)、以及有限的 TCP 选项(如 MSS、SACK),不包含窗口字段; -
string模块可匹配载荷内容,但窗口大小在 TCP 头部,不在应用层载荷中,且string默认不扫描 IP/TCP 头部; -
u32模块理论上可通过偏移量提取任意头部字段,但实际受限于 netfilter 的 skb 数据访问机制:TCP 窗口字段在 skb->nh.iph->saddr 之后固定偏移处,但需精确计算字节位置,并受 IP 分片、TCP 选项长度变化影响,极不稳定、不可靠,不推荐用于生产环境识别扫描器。
所以,不能依赖 iptables 原生能力“精准识别 TCP 窗口大小异常”来防御扫描器。
那为什么有人提到“窗口大小能识别扫描器”?
因为部分扫描器(如某些定制化 Nmap 脚本、ZMap 变种)为加快探测速度,会发送 TCP SYN 包并固定使用极小(如 0)、极大(如 65535)或非常规值(如 1024、4096)作为初始窗口,而正常操作系统栈有默认行为(Linux 常为 29200,Windows 为 64240,FreeBSD 为 131072 等)。但这属于统计性启发特征,不是确定性规则。
真正可行的落地方式是分层处理:
用 iptables 配合连接状态与速率做间接压制
TCP 窗口本身不可靠,但扫描器行为有强规律:
- 短时间内对大量 IP 或端口发起 SYN 连接;
- 大量连接停留在 SYN_RECV 状态;
- 单 IP 在极短时间内触发大量 NEW 连接。
这些可用 iptables 稳定识别:
-
限制单 IP 新连接速率(防 SYN Flood / 扫描泛滥):
iptables -I INPUT -p tcp -m state --state NEW -m limit --limit 20/sec --limit-burst 40 -j ACCEPT iptables -I INPUT -p tcp -m state --state NEW -j DROP
-
结合 recent 模块标记高频扫描源(例如 30 秒内尝试 >10 个不同端口):
iptables -I INPUT -p tcp -m state --state NEW -m recent --name portscan --rcheck --seconds 30 --hitcount 10 -j DROP iptables -I INPUT -p tcp -m state --state NEW -m recent --name portscan --set --mask 255.255.255.255
用 tcpdump + 脚本做窗口特征离线分析(非实时拦截)
若需验证某流量是否含异常窗口值,可抓包后解析:
tcpdump -nn -i eth0 'tcp[tcpflags] & (tcp-syn|tcp-ack) == tcp-syn' -c 100 -w syn.pcap # 然后用 tshark 或自定义脚本读取 tcp.window_size 字段 tshark -r syn.pcap -Y 'tcp.window_size 65000' -T fields -e ip.src -e tcp.window_size
这类分析适合审计、溯源,不能替代实时防火墙策略。
真正可靠的窗口感知防御要靠更高层工具
-
Suricata / Zeek(Bro):支持深度协议解析,可写规则检测
tcp.window ; - eBPF 程序(如 using bpftrace):可安全读取 skb 中完整 TCP 头,包括窗口字段,适合内核态实时过滤;
-
内核参数调优:
net.ipv4.tcp_invalid_ratelimit、net.ipv4.tcp_syncookies=1等可缓解异常窗口引发的状态耗尽。
不复杂但容易忽略:与其纠结窗口值,不如守住连接节奏和状态合法性。SYN 包的标志组合、源频次、响应行为,比窗口数字本身更具区分度。










