Linux运维10 min read

Linux 防火墙实战:iptables/nftables 规则编排与 tc 流量控制

一、一次被 DDoS 打挂的教训

去年帮一个客户排查服务器,现象很诡异:CPU 不到 20%,带宽也没跑满,但 SSH 就是连不上、网站就是 502。最后发现是海量半连接(SYN Flood)把 连接跟踪表(conntrack) 打满了——dmesg 里满屏 nf_conntrack: table full, dropping packet

那次之后我明白:防火墙不是"挡不挡端口"的开关,而是一套需要按流量特征精细编排的防御体系。本文把 iptables、nftables、fail2ban、tc 四件套串起来讲清楚。

二、iptables 四表五链:先建立心智模型

iptables 的复杂度来自它把规则分到了"表(table)"和"链(chain)"两个维度:

                   数据包进入
                       │
         ┌─────────────▼─────────────┐
         │  PREROUTING (路由前)        │
         └─────────────┬─────────────┘
                       │
              ┌────────▼────────┐
              │  路由判断        │
              └───┬────────┬───┘
         本机流量  │        │  转发流量
                  │        │
        ┌─────────▼──┐   ┌─▼──────────┐
        │ INPUT      │   │ FORWARD     │
        │ (本机接收) │   │ (转发其他机)│
        └─────────┬──┘   └─┬──────────┘
                  │        │
         ┌────────▼────────▼────────┐
         │  POSTROUTING (路由后)      │
         └──────────────────────────┘
                  │
                  ▼ 出网卡

五链:PREROUTING、INPUT、FORWARD、OUTPUT、POSTROUTING 四表(优先级从高到低):

  • raw:是否跳过连接跟踪
  • mangle:修改包头(TTL、TOS、MARK)
  • nat:地址转换(SNAT/DNAT)
  • filter:过滤(最常用,默认表)

最常用的 filter 表三链:INPUT(进本机)、FORWARD(转发)、OUTPUT(本机出)。

三、生产级基础规则:先封锁,再按需开放

新手最容易犯的错是"先全放行再想收",结果漏配留下后门。正确姿势是默认 DROP,白名单开放

# 1. 清空旧规则(测试时谨慎!远程执行可能把自己踢下线)
iptables -F
iptables -X

# 2. 默认策略:进和转发都 DROP
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT

# 3. 允许回环
iptables -A INPUT -i lo -j ACCEPT

# 4. 允许已建立/相关的连接(关键!否则响应包也进不来)
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

# 5. 白名单开放服务端口
iptables -A INPUT -p tcp --dport 22 -s 10.0.0.0/8 -j ACCEPT   # SSH 仅内网
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT

# 6. 防 SYN Flood:限制单个 IP 的新连接速率
iptables -A INPUT -p tcp --syn -m limit --limit 20/s --limit-burst 50 -j ACCEPT
iptables -A INPUT -p tcp --syn -j DROP

# 7. 丢弃无效包
iptables -A INPUT -m state --state INVALID -j DROP

避坑 1:远程操作时千万别先执行 -P INPUT DROP 再配规则——一旦网络抖动或命令中断,你会被锁在门外。安全做法是用 iptables-apply 命令,它会在 60 秒无确认后自动回滚:

iptables-apply -t 60 your-rules.sh

四、nftables:iptables 的现代替代

iptables 实际是 nf_tables 内核框架的用户态前端,命令分散(iptables/ip6tables/ebtables),语法反人类。RHEL 8+、Debian 10+ 已默认推荐 nftables,统一语法、性能更好、支持集合(set)和字典(map)。

等价的 nftables 配置:

# 创建表与基础链
nft add table inet filter
nft add chain inet filter input { type filter hook input priority 0\; policy drop\; }
nft add chain inet filter forward { type filter hook forward priority 0\; policy drop\; }

# 允许回环与已建立连接
nft add rule inet filter input iifname "lo" accept
nft add rule inet filter input ct state established,related accept

# 用 set 管理白名单 IP,比逐条写规则优雅得多
nft add set inet filter ssh_whitelist { type ipv4_addr\; }
nft add element inet filter ssh_whitelist { 10.0.0.0/8 }
nft add rule inet filter input tcp dport 22 ip saddr @ssh_whitelist accept

# 开放 Web 端口
nft add rule inet filter input tcp dport { 80, 443 } accept

# 防 SYN Flood
nft add rule inet filter input tcp flags syn limit rate 20/second burst 50 packets accept
nft add rule inet filter input tcp flags syn drop

nftables 还支持把整个配置写成一个文件,用 nft -f ruleset.conf 原子加载,比 iptables 一行行敲可靠得多。Red Hat 系用 nft list ruleset > /etc/nftables.conf 持久化,Debian 系启用 nftables.service 即可。

避坑 2:iptables 和 nftables 同时跑会互相看不见对方的规则(虽然共享内核 nf_tables),极易造成"我明明加了规则怎么不生效"。生产机二选一,迁移时彻底禁用另一个:

# 确认没有 iptables 规则残留
iptables-save | wc -l   # 应只剩默认链
systemctl disable --now iptables 2>/dev/null

五、fail2ban:自动封禁爆破 IP

防火墙白名单解决了"谁来连",但 22 端口暴露在外网时,暴力破解会刷爆日志。fail2ban 监听日志,命中失败阈值就动态加 iptables/nftables 规则封 IP:

# /etc/fail2ban/jail.local
[DEFAULT]
bantime  = 1h
findtime = 10m
maxretry = 5
banaction = nftables-multiport   # 对应你的防火墙后端

[sshd]
enabled = true
port    = 22
filter  = sshd
logpath = /var/log/secure
maxretry = 3

验证生效:

fail2ban-client status sshd
# Status for the jail
# |- Filter
# |  |- Currently failed: 2
# |  `- Total failed:     47
# `- Actions
#    |- Currently banned: 3
#    `- Banned IP list:   182.92.x.x 45.33.x.x 1.2.3.4

避坑 3:fail2ban 的 banaction 必须和机器实际用的防火墙匹配。用 nftables 却配了 iptables-multiport,封禁规则会写进 iptables 而你的流量走 nftables 链,等于没封。

六、tc 流量控制:给带宽做 QoS

防火墙管"能不能通",tc(Traffic Control)管"谁先走、走多快"。典型场景:服务器出口带宽 100Mbps,夜里备份把带宽占满,白天 API 响应就抖。用 tc 给备份流量限速、给业务流量保证优先级:

# 在出网卡 eth0 上建立根 qdisc(htb 分层令牌桶)
tc qdisc add dev eth0 root handle 1: htb default 30

# 总带宽 100Mbps
tc class add dev eth0 parent 1: classid 1:1 htb rate 100mbit

# 业务类:保证 70Mbps,可突发到 100M
tc class add dev eth0 parent 1:1 classid 1:10 htb rate 70mbit ceil 100mbit prio 1
# 备份类:限速 30Mbps,最低保障 5M
tc class add dev eth0 parent 1:1 classid 1:30 htb rate 5mbit ceil 30mbit prio 2

# 用 iptables MARK 打标,把备份流量(目的端口 873 rsync)标记为 30
iptables -t mangle -A OUTPUT -p tcp --dport 873 -j MARK --set-mark 30

# 按 MARK 把流量导入对应 class
tc filter add dev eth0 parent 1: handle 30 fw classid 1:30
tc filter add dev eth0 parent 1: handle 10 fw classid 1:10

这样业务流量永远优先,备份只能在剩余带宽里"捡漏",再也不会把 API 拖垮。

避坑 4:tc 规则默认重启即失,必须写进网络启动脚本或 NetworkManager-dispatcher。一个常见的持久化方式:

# /etc/network/if-up.d/tc-limit
#!/bin/bash
[ "$IFACE" = "eth0" ] || exit 0
tc qdisc add dev eth0 root handle 1: htb default 30
# ... 其余规则
chmod +x /etc/network/if-up.d/tc-limit

七、排错全流程

规则不生效时,按这个顺序查:

# 1. 看连接跟踪表是否打满(前文 DDoS 案例)
cat /proc/sys/net/netfilter/nf_conntrack_count
cat /proc/sys/net/netfilter/nf_conntrack_max

# 2. 看包到底命中了哪条规则(iptables 计数)
iptables -L INPUT -v -n --line-numbers

# 3. 用 TRACE 追踪单个包的路径(调试神器)
iptables -t raw -A PREROUTING -p tcp --dport 443 -j TRACE
# 然后 dmesg | grep TRACE 看包走过的每个链

# 4. nftables 对应追踪
nft add rule inet filter input tcp dport 443 meta nftrace set 1
# nft monitor trace

避坑 5conntrack_max 默认值往往偏小(默认 65536)。高并发服务器要调大,否则正常流量也会被当"表满丢包":

sysctl -w net.netfilter.nf_conntrack_max=262144
echo "net.netfilter.nf_conntrack_max=262144" >> /etc/sysctl.conf

八、小结

防火墙体系四件套的职责边界:

工具 管什么 典型场景
iptables/nftables 能不能通、地址怎么转 端口开放、黑白名单、NAT
fail2ban 谁被临时拉黑 防 SSH/Web 暴力破解
tc 谁先走、走多快 带宽限速、QoS 保障
conntrack 连接状态跟踪 状态防火墙的底层支撑

把它们组合起来,一台暴露在公网的服务器就能做到:该开的端口精准开放、爆破 IP 自动封禁、关键业务带宽有保障、连接表不被打爆。这才是生产级的安全水位。

下一篇可以深入 eBPF + XDP,用更底层的手段在网卡层面直接丢弃攻击流量,把防御推进到内核协议栈的最前端。

分享:

相关文章

评论区