Linux中iptables的-m connmark模块通过连接标记实现异常协议流量清洗:先在mangle表识别并标记异常连接(如非HTTP明文流量),再在filter表基于connmark统一限速、丢弃或重定向,确保全程一致性处理,且需注意规则顺序、mark同步及持久化保存。

在 Linux 中,利用 iptables 的 -m connmark 模块实现异常协议流量清洗,核心思路是:先识别异常流量(如非法端口、畸形包、非标准协议行为),打上连接标记(connmark),再基于该标记对整个连接的后续数据包进行统一限速、丢弃或重定向。这比单纯用 -m state 或单包匹配更可靠,因为能保持连接粒度的一致性处理。
一、理解 connmark 与 connection tracking 的关系
connmark 是作用于连接跟踪(conntrack)条目的标记,不是单个数据包的 mark。一旦给某连接打上 connmark,该连接所有后续进出包(无论方向)在经过 PREROUTING、OUTPUT、FORWARD 链时,都能通过 -m connmark --mark 匹配到它。这是实现“一次识别、全程清洗”的基础。
注意:
- connmark 不会自动继承到 packet mark(即 -j MARK 设置的 nfmark),需显式用 -j CONNMARK --save-mark 或 --restore-mark 同步;
- 所有涉及 connmark 的规则,建议放在 raw 表(绕过 conntrack)之前或 mangle 表早期(如 PREROUTING 开头),避免被状态模块提前处理。
二、典型异常协议流量识别与标记流程
以清洗“TCP 连接中混入非 HTTP 的明文协议(如 Telnet、FTP 控制流)”为例:
- 在
raw表跳过 conntrack(可选,避免干扰):iptables -t raw -A PREROUTING -p tcp --dport 80 -j NOTRACK - 在
mangle表PREROUTING链识别异常特征(如 TCP payload 开头非GET/POST/HTTP/):iptables -t mangle -A PREROUTING -p tcp --dport 80 -m string ! --string "GET " --algo bm -j CONNMARK --save-mark --mask 0xffffffff --or-mark 0x00000001
(此例将异常连接标记为 0x1;注意string模块需内核支持,且仅匹配首段 payload) - 确保连接建立后也能捕获(如三次握手完成后的第一个数据包才含 payload),可结合
-m state --state ESTABLISHED,RELATED提高命中率。
三、基于 connmark 的清洗动作配置
标记完成后,在 filter 表中对带标记的连接执行清洗:
- 直接丢弃整个连接的所有后续包:
iptables -t filter -A FORWARD -m connmark --mark 0x1 -j DROP - 限速(防扫描/探测):
iptables -t filter -A FORWARD -m connmark --mark 0x1 -m limit --limit 5/sec --limit-burst 10 -j ACCEPTiptables -t filter -A FORWARD -m connmark --mark 0x1 -j DROP - 重定向至 honeypot(需配合 DNAT):
iptables -t nat -A PREROUTING -m connmark --mark 0x1 -j DNAT --to-destination 192.168.100.99:22
关键点:清洗规则必须放在通用放行规则(如 -j ACCEPT -m state --state ESTABLISHED,RELATED)之前,否则标记连接会被提前放过。
四、持久化与调试技巧
connmark 规则重启后失效,需保存:
- 保存规则:
iptables-save > /etc/iptables/rules.v4(Debian/Ubuntu)iptables-save > /etc/sysconfig/iptables(CentOS/RHEL) - 查看当前 conntrack 标记状态:
conntrack -L | grep "mark=1"(显示标记为 1 的连接) - 实时跟踪匹配过程:
iptables -t mangle -A PREROUTING -m connmark --mark 0x1 -j LOG --log-prefix "[CONN-CLEAN] "
再配合tail -f /var/log/kern.log观察日志。
清洗效果依赖于初始识别精度。建议先用 -j LOG 替代 -j DROP 观察一周,确认误杀率低于 0.1% 再启用真实清洗。











