强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

iptables 完全指南 / 第 07 章:raw 表与连接跟踪优化

第 07 章:raw 表与连接跟踪优化

本章目标:理解 raw 表在连接跟踪体系中的位置,掌握 NOTRACK 的使用方法,学会优化大规模环境下的连接跟踪性能。


7.1 raw 表概述

raw 表是 iptables 中优先级最高的表,它在连接跟踪(conntrack)模块处理之前执行。其核心用途是控制哪些数据包需要进行连接跟踪

7.1.1 raw 表在数据包处理中的位置

数据包进入内核
       │
       ▼
┌──────────────┐
│ raw 表        │ ← 优先级最高,在 conntrack 之前
│ PREROUTING   │   可以决定是否跳过连接跟踪
└──────┬───────┘
       │
       ▼
┌──────────────┐
│ 连接跟踪      │ ← nf_conntrack 处理
│ (conntrack)  │   记录连接状态
└──────┬───────┘
       │
       ▼
┌──────────────┐
│ mangle 表     │
│ nat 表        │
│ filter 表     │
└──────────────┘

7.1.2 raw 表支持的链

用途
PREROUTING在入站数据包进入 conntrack 之前处理
OUTPUT在本机产生的数据包进入 conntrack 之前处理

注意:raw 表只有两条链,不支持 INPUT、FORWARD、POSTROUTING。


7.2 NOTRACK 目标

7.2.1 NOTRACK 的作用

NOTRACK(或 --jump NOTRACK)告诉内核不对匹配的数据包进行连接跟踪。被标记为 NOTRACK 的数据包:

  • 不进入 conntrack 表:不占用 conntrack 条目
  • 没有连接状态:不能使用 -m conntrack --ctstate 匹配
  • 不能使用 NAT:NAT 依赖连接跟踪,NOTRACK 的包不能做 NAT
  • 性能提升:减少了内核处理开销

7.2.2 NOTRACK 基本用法

# 不跟踪所有 UDP 53 流量(DNS 查询通常很短)
iptables -t raw -A PREROUTING -p udp --dport 53 -j NOTRACK
iptables -t raw -A OUTPUT -p udp --dport 53 -j NOTRACK

# 不跟踪特定主机的流量
iptables -t raw -A PREROUTING -s 10.0.0.100 -j NOTRACK
iptables -t raw -A OUTPUT -d 10.0.0.100 -j NOTRACK

# 不跟踪 NFS 流量(高吞吐场景)
iptables -t raw -A PREROUTING -p tcp --dport 2049 -j NOTRACK
iptables -t raw -A PREROUTING -p udp --dport 2049 -j NOTRACK
iptables -t raw -A OUTPUT -p tcp --dport 2049 -j NOTRACK
iptables -t raw -A OUTPUT -p udp --dport 2049 -j NOTRACK

7.2.3 NOTRACK 的影响

使用 NOTRACK 前:

┌───────────┐     ┌───────────┐     ┌───────────────┐
│ 数据包     │────→│ conntrack │────→│ mangle/nat/   │
│           │     │ 记录连接   │     │ filter 处理   │
└───────────┘     └───────────┘     └───────────────┘
                      │
                      ▼
                 conntrack 表占用内存
                 可使用 -m conntrack --ctstate
                 可使用 NAT

使用 NOTRACK 后:

┌───────────┐     ┌───────────────────┐
│ 数据包     │────→│ mangle/nat/filter │
│           │     │ 处理              │
└───────────┘     └───────────────────┘
                      │
                      ▼
                 不经过 conntrack
                 不能使用 -m conntrack --ctstate
                 不能使用 NAT
                 节省内核内存和 CPU

7.3 连接跟踪机制

7.3.1 conntrack 模块简介

连接跟踪(Connection Tracking)是 Netfilter 的核心模块,它为每个经过防火墙的网络连接维护一条记录,包括:

字段说明
源/目的 IP连接双方的地址
源/目的端口连接双方的端口
协议TCP/UDP/ICMP 等
状态NEW/ESTABLISHED/RELATED/INVALID
超时时间不同协议的超时时间不同
NAT 信息SNAT/DNAT 映射关系

7.3.2 查看 conntrack 信息

# 查看所有连接跟踪条目
conntrack -L

# 按协议过滤
conntrack -L -p tcp

# 实时监控新建连接
conntrack -E

# 统计连接跟踪条目数量
conntrack -C

# 查看 conntrack 模块参数
sysctl -a | grep net.netfilter.nf_conntrack

7.3.3 conntrack 表大小

# 查看当前连接跟踪表大小
sysctl net.netfilter.nf_conntrack_max
# net.netfilter.nf_conntrack_max = 65536

# 查看当前已使用的条目数
cat /proc/sys/net/netfilter/nf_conntrack_count

# 查看 conntrack 表占用的内存
grep -i conntrack /proc/slabinfo

7.4 连接跟踪性能优化

7.4.1 调整 conntrack 表大小

# 计算所需内存(每条记录约 300 字节)
# 100 万条连接 ≈ 300MB 内存
# 26 万条连接 ≈ 78MB 内存

# 增大连接跟踪表(适合高并发服务器)
sysctl -w net.netfilter.nf_conntrack_max=262144

# 持久化配置
echo "net.netfilter.nf_conntrack_max = 262144" >> /etc/sysctl.conf

# 增大 hash 表桶数(应为 max 的 1/4 到 1/8)
echo 65536 > /sys/module/nf_conntrack/parameters/hashsize
# 或
echo "options nf_conntrack hashsize=65536" >> /etc/modprobe.d/conntrack.conf

7.4.2 调整超时时间

# 查看当前超时设置
sysctl -a | grep net.netfilter.nf_conntrack.*timeout

# TCP 超时参数
sysctl -a | grep net.netfilter.nf_conntrack_tcp_timeout
参数默认值建议值说明
tcp_timeout_syn_sent12030SYN 等待时间
tcp_timeout_syn_recv6015SYN+ACK 等待时间
tcp_timeout_established4320003600已建立连接的超时(5天→1小时)
tcp_timeout_fin_wait12030FIN_WAIT 状态超时
tcp_timeout_close_wait6015CLOSE_WAIT 状态超时
tcp_timeout_time_wait12030TIME_WAIT 状态超时
udp_timeout3010UDP 流超时
udp_timeout_stream18060UDP 流超时
icmp_timeout3010ICMP 超时
generic_timeout600120其他协议超时
# 优化 TCP 超时(高并发 Web 服务器)
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_established=3600
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_fin_wait=30
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_close_wait=15
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_time_wait=30
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_syn_sent=30
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_syn_recv=15

# 优化 UDP 超时
sysctl -w net.netfilter.nf_conntrack_udp_timeout=10
sysctl -w net.netfilter.nf_conntrack_udp_timeout_stream=60

7.4.3 监控 conntrack 状态

#!/bin/bash
# conntrack 监控脚本

# 获取当前使用量和最大值
COUNT=$(cat /proc/sys/net/netfilter/nf_conntrack_count)
MAX=$(cat /proc/sys/net/netfilter/nf_conntrack_max)
USAGE=$((COUNT * 100 / MAX))

echo "conntrack 使用率: $COUNT / $MAX ($USAGE%)"

# 如果使用率超过 80%,发出警告
if [ $USAGE -gt 80 ]; then
    echo "WARNING: conntrack 使用率过高!"
    # 记录到系统日志
    logger -t conntrack-monitor "WARNING: Usage $USAGE% ($COUNT/$MAX)"
fi

# 查看连接状态分布
echo ""
echo "连接状态分布:"
conntrack -L 2>/dev/null | awk '{print $4}' | sort | uniq -c | sort -rn | head -10

7.5 业务场景优化方案

7.5.1 高并发 Web 服务器

#!/bin/bash
# ═══════════════════════════════════════════════════
# 高并发 Web 服务器连接跟踪优化
# ═══════════════════════════════════════════════════

# ─── 1. 调整内核参数 ───

# 增大 conntrack 表
sysctl -w net.netfilter.nf_conntrack_max=524288
echo 131072 > /sys/module/nf_conntrack/parameters/hashsize

# 缩短超时时间
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_established=1800
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_time_wait=15
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_fin_wait=15
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_close_wait=10
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_syn_sent=15
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_syn_recv=10

# ─── 2. raw 表跳过不需要跟踪的流量 ───

# 跳过内网心跳检测(如 keepalived VRRP)
iptables -t raw -A PREROUTING -p vrrp -j NOTRACK
iptables -t raw -A OUTPUT -p vrrp -j NOTRACK

# 跳过内网集群通信(如 Redis 哨兵)
iptables -t raw -A PREROUTING -p tcp --dport 26379 -j NOTRACK
iptables -t raw -A OUTPUT -p tcp --dport 26379 -j NOTRACK

7.5.2 DNS 缓存服务器

#!/bin/bash
# DNS 服务器不需要对 UDP 53 做连接跟踪
# DNS 查询通常是无状态的 UDP 一问一答

# 跳过 DNS 查询的连接跟踪
iptables -t raw -A PREROUTING -p udp --dport 53 -j NOTRACK
iptables -t raw -A OUTPUT -p udp --sport 53 -j NOTRACK

# 注意:如果使用了 NAT,不能对 DNS 流量使用 NOTRACK

7.5.3 视频流媒体服务器

#!/bin/bash
# 视频流媒体服务器的优化
# 大量 UDP 流媒体流量会快速填满 conntrack 表

# 跳过 RTMP 流量的连接跟踪
iptables -t raw -A PREROUTING -p tcp --dport 1935 -j NOTRACK
iptables -t raw -A OUTPUT -p tcp --dport 1935 -j NOTRACK

# 跳过 HLS/DASH 分片下载(大量短连接)
iptables -t raw -A PREROUTING -p tcp --dport 8080 -j NOTRACK
iptables -t raw -A OUTPUT -p tcp --dport 8080 -j NOTRACK

# 注意:如果使用了 NOTRACK,必须在 filter 表中显式添加允许规则
# 因为不能使用 -m conntrack --ctstate ESTABLISHED,RELATED
iptables -A INPUT -p tcp --dport 1935 -j ACCEPT
iptables -A INPUT -p tcp --dport 8080 -j ACCEPT

7.6 raw 表与其他表的协作

7.6.1 NOTRACK 后的规则编写

当数据包被 NOTRACK 标记后,它没有连接状态,因此:

# ❌ 这条规则不会匹配 NOTRACK 的数据包
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

# ✅ 正确做法:显式匹配双向流量
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A OUTPUT -p tcp --sport 80 -j ACCEPT

7.6.2 混合模式:部分流量跟踪,部分不跟踪

#!/bin/bash
# ═══════════════════════════════════════════════════
# 混合模式示例
# Web 流量:使用连接跟踪(需要 conntrack 状态匹配)
# NFS 流量:跳过连接跟踪(高性能需求)
# ═══════════════════════════════════════════════════

# ─── raw 表:跳过 NFS 的连接跟踪 ───
iptables -t raw -A PREROUTING -p tcp --dport 2049 -j NOTRACK
iptables -t raw -A PREROUTING -p udp --dport 2049 -j NOTRACK
iptables -t raw -A OUTPUT -p tcp --sport 2049 -j NOTRACK
iptables -t raw -A OUTPUT -p udp --sport 2049 -j NOTRACK

# ─── filter 表 ───

# 已建立连接(仅对跟踪的流量生效)
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

# 回环接口
iptables -A INPUT -i lo -j ACCEPT

# Web 流量(被连接跟踪)
iptables -A INPUT -p tcp -m multiport --dports 80,443 -j ACCEPT

# NFS 流量(未被连接跟踪,需要双向显式允许)
iptables -A INPUT -p tcp --dport 2049 -j ACCEPT
iptables -A INPUT -p udp --dport 2049 -j ACCEPT

# SSH
iptables -A INPUT -p tcp --dport 22 -j ACCEPT

# 默认拒绝
iptables -P INPUT DROP

7.7 conntrack 常见问题排查

7.7.1 conntrack 表满

症状dmesg 中出现以下日志:

nf_conntrack: table full, dropping packet

排查步骤

# 1. 查看当前条目数
conntrack -C

# 2. 查看最大值
sysctl net.netfilter.nf_conntrack_max

# 3. 查看是否有大量半开连接
conntrack -L | grep SYN_SENT | wc -l

# 4. 查看是否有大量 TIME_WAIT
conntrack -L | grep TIME_WAIT | wc -l

解决方案

# 临时方案:增大表
sysctl -w net.netfilter.nf_conntrack_max=262144

# 长期方案:
# 1. 缩短超时时间
# 2. 对不需要跟踪的流量使用 NOTRACK
# 3. 应用层使用连接池减少短连接

7.7.2 conntrack 导致的 NAT 问题

症状:修改了 DNAT 规则后,已有连接仍然走旧规则

原因:conntrack 表中缓存了旧的 NAT 映射

解决方案

# 清除 conntrack 表中的相关条目
conntrack -D -p tcp --dport 80

# 或清除所有条目(会导致已有连接断开)
conntrack -F

7.8 raw 表的高级用法

7.8.1 配合 nftables 使用 raw 表

# nftables 等价写法
nft add table inet raw_table
nft add chain inet raw_table prerouting { type filter hook prerouting priority -300 \; }
nft add rule inet raw_table prerouting udp dport 53 notrack

7.8.2 使用 TPROXY 进行透明代理

# TPROXY 需要 raw 表中的 NOTRACK 配合

# 在 raw 表中跳过连接跟踪
iptables -t raw -A PREROUTING -p tcp --dport 80 -j NOTRACK

# 在 mangle 表中使用 TPROXY
iptables -t mangle -A PREROUTING -p tcp --dport 80 \
  -j TPROXY --tproxy-mark 0x1/0x1 --on-port 3129

# 策略路由
ip rule add fwmark 1 lookup 100
ip route add local 0.0.0.0/0 dev lo table 100

7.9 注意事项

⚠️ NOTRACK 与 NAT 不兼容:被 NOTRACK 标记的数据包不能使用 NAT。如果流量需要 NAT,不要使用 NOTRACK。

⚠️ NOTRACK 与状态匹配不兼容:被 NOTRACK 标记的数据包没有连接状态,不能使用 -m conntrack --ctstate ESTABLISHED,RELATED。必须显式允许双向流量。

⚠️ 清空 conntrack 表的风险conntrack -F 会清除所有连接跟踪记录,导致所有已有连接的状态信息丢失,可能引起网络中断。

⚠️ hashsize 的设置:hash 表的桶数应该大于 conntrack_max / 4,否则哈希冲突会导致性能下降。


7.10 扩展阅读

资源说明
man conntrackconntrack 工具手册
man conntrackd连接跟踪同步守护进程手册
Netfilter conntrack 文档内核文档中的连接跟踪部分
cat /proc/net/nf_conntrack直接查看 conntrack 表

本章小结

概念要点
raw 表优先级最高,在 conntrack 之前执行
NOTRACK跳过连接跟踪,节省内存和 CPU
conntrack_max连接跟踪表的最大条目数
超时优化缩短不必要长的超时时间
hashsize哈希桶数,影响查找性能
NOTRACK 限制不能使用 NAT 和状态匹配

下一章第 08 章:扩展匹配模块,将学习各种高级匹配条件的用法。