概述

iptables 是 Linux 内核 netfilter 框架的用户空间工具,自 2001 年起成为 Linux 防火墙的事实标准。它通过规则表(table)和规则链(chain)的结构,对进出系统的网络数据包进行过滤、修改和转发控制。

虽然 nftables 已被各大发行版列为默认,但 iptables 依然广泛存在于现有生产环境,理解 iptables 也是学习 nftables 的基础。


核心概念

数据包流向

理解 iptables 必须先理解数据包在 Linux 内核中的流转路径:

                        ┌──────────┐
                        │   INPUT   │  → 本地进程
                        └──────────┘
                            ▲
                            │
    ┌──────────┐    ┌──────────┐    ┌──────────┐
    │  PREROUTING│──▶│   FORWARD │──▶│ POSTROUTING│
    │  (路由前)  │    │  (转发)   │    │  (路由后)  │
    └──────────┘    └──────────┘    └──────────┘
                            │
                            ▼
                        ┌──────────┐
                        │  OUTPUT   │  ← 本地进程
                        └──────────┘

数据包经过的链(Chain):

方向 经过链
入站 → 本地进程 PREROUTING → INPUT
本地进程 → 出站 OUTPUT → POSTROUTING
经过本机转发 PREROUTING → FORWARD → POSTROUTING

四表五链

iptables 的核心结构是 4 张表(Table)5 条链(Chain)

5 条内置链:

链名 作用 方向
INPUT 处理入站数据包(目标为本机) 入站
OUTPUT 处理出站数据包(本机发出) 出站
FORWARD 处理转发的数据包(路由经过本机) 转发
PREROUTING 路由决策前处理数据包 入站(路由前)
POSTROUTING 路由决策后处理数据包 出站(路由后)

4 张表:

表名 作用 挂载的链
filter 包过滤(默认表,最常用) INPUT、OUTPUT、FORWARD
nat 网络地址转换(NAT、端口转发) PREROUTING、OUTPUT、POSTROUTING
mangle 数据包修改(TTL、TOS、标记等) 全部 5 链
raw 连接跟踪豁免(NOTRACK) PREROUTING、OUTPUT

规则匹配与动作

规则由两部分组成:

iptables -A <链> <匹配条件> -j <动作>

常见匹配条件:

匹配 示例 说明
源 IP -s 192.168.1.0/24 匹配来源地址
目标 IP -d 10.0.0.1 匹配目标地址
协议 -p tcp 匹配协议(tcp/udp/icmp)
端口 --dport 80 匹配目标端口
网卡 -i eth0 匹配入站网卡
状态 -m state --state NEW 匹配连接状态
并发 -m connlimit --connlimit-above 10 限制并发连接数

常见动作(target):

动作 说明
ACCEPT 允许通过
DROP 丢弃(不回复,客户端会等到超时)
REJECT 拒绝(回复拒绝消息,客户端立即知道被拒)
LOG 记录日志(不阻止,继续匹配下一条)
SNAT 源地址转换(用于 NAT 出站)
DNAT 目标地址转换(用于端口转发)
MASQUERADE 动态 SNAT(用于 PPPoE 拨号等动态 IP)
RETURN 返回上级链

安装

Debian / Ubuntu

# 安装 iptables(通常系统自带)
sudo apt update
sudo apt install iptables

# 额外工具:规则持久化
sudo apt install iptables-persistent

# IPv6 也需要的话
sudo apt install ip6tables

RHEL / CentOS 7 / Rocky 8

# CentOS 7 默认使用 legacy iptables
sudo yum install iptables iptables-services

# 启动并启用
sudo systemctl start iptables
sudo systemctl enable iptables

# CentOS 8+ / Rocky 9 有 iptables-nft 兼容层
sudo dnf install iptables-nft

查看当前版本

iptables --version

# 输出示例
# iptables v1.8.7 (nf_tables)          → 运行在 nftables 后端兼容模式
# iptables v1.4.21 (legacy)            → 传统 iptables 模式

快速上手

查看规则

# 查看 filter 表规则
iptables -L -n -v

# 查看 nat 表规则
iptables -t nat -L -n -v

# 查看规则编号(便于删除/插入)
iptables -L --line-numbers

# 仅查看 INPUT 链
iptables -L INPUT -n -v

参数说明:

参数 含义
-L 列出规则
-n 不解析 IP 为域名(显示更快)
-v 显示详细信息(包计数、字节数)
--line-numbers 显示规则编号
-t nat 指定表(默认是 filter)

基本防火墙规则

# ===== 默认策略 =====

# 将 INPUT 默认策略设为 DROP(拒绝所有入站)
iptables -P INPUT DROP

# 将 OUTPUT 默认策略设为 DROP(拒绝所有出站——严格模式)
iptables -P OUTPUT DROP

# 将 FORWARD 默认策略设为 DROP
iptables -P FORWARD DROP

# ===== 允许已建立的连接 =====

# 允许已建立的和相关的连接(一定要加,否则 SSH 都会断)
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A OUTPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

# ===== 允许回环接口 =====

iptables -A INPUT -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT

# ===== 开放常用服务 =====

# 允许 SSH(很重要,远程服务器一定要先开这个再改默认策略)
iptables -A INPUT -p tcp --dport 22 -j ACCEPT

# 允许 HTTP/HTTPS
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT

# 允许 ICMP(Ping)
iptables -A INPUT -p icmp -j ACCEPT

# 允许 DNS 出站(如果默认 OUTPUT 是 DROP)
iptables -A OUTPUT -p udp --dport 53 -j ACCEPT
iptables -A OUTPUT -p tcp --dport 53 -j ACCEPT

# ===== 限制 SSH 暴力破解 =====

# 每分钟最多 5 个 SSH 连接
iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --set --name SSH
iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --update --seconds 60 --hitcount 5 --name SSH -j DROP

一个完整的示例脚本

#!/bin/bash

# 清空所有规则
iptables -F
iptables -X
iptables -t nat -F
iptables -t mangle -F

# 默认策略:拒绝所有入站和转发,允许所有出站
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT

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

# 允许已建立的连接
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

# 允许 SSH(改端口的话改这里)
iptables -A INPUT -p tcp --dport 22 -j ACCEPT

# 允许 HTTP/HTTPS
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT

# 允许 Ping
iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT

# 记录被拒绝的包(可选)
iptables -A INPUT -j LOG --log-prefix "IPTABLES-DROP: " --log-level 4

进阶用法

NAT(网络地址转换)

场景 1:共享上网(MASQUERADE)

# 启用 IP 转发
echo 1 > /proc/sys/net/ipv4/ip_forward

# 内网网段从 eth0 出站时做 SNAT
iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth0 -j MASQUERADE

场景 2:端口转发(DNAT)

# 将本机 8080 端口转发到内网 10.0.0.2:80
iptables -t nat -A PREROUTING -p tcp --dport 8080 -j DNAT --to-destination 10.0.0.2:80

# 需要 FORWARD 链也放行
iptables -A FORWARD -p tcp -d 10.0.0.2 --dport 80 -j ACCEPT

限速(rate limiting)

# 限制 ICMP 每秒不超过 10 个
iptables -A INPUT -p icmp -m limit --limit 10/second -j ACCEPT
iptables -A INPUT -p icmp -j DROP

# 限制 SSH 连接速率
iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m limit --limit 3/min -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -m state --state NEW -j DROP

黑名单 IP

# 屏蔽某个 IP
iptables -A INPUT -s 1.2.3.4 -j DROP

# 屏蔽整个网段
iptables -A INPUT -s 10.0.0.0/24 -j DROP

# 从文件加载 IP 黑名单
for ip in $(cat blacklist.txt); do
    iptables -A INPUT -s $ip -j DROP
done

规则管理操作

# 在指定位置插入规则(第 3 条)
iptables -I INPUT 3 -p tcp --dport 8080 -j ACCEPT

# 删除指定规则(通过编号)
iptables -D INPUT 3

# 删除指定规则(通过内容匹配)
iptables -D INPUT -p tcp --dport 8080 -j ACCEPT

# 替换某条规则
iptables -R INPUT 3 -p tcp --dport 9090 -j ACCEPT

# 清空某条链
iptables -F INPUT

# 清空所有规则
iptables -F
iptables -X
iptables -t nat -F
iptables -t mangle -F

规则持久化

iptables 的规则在重启后会丢失,需要手动保存和恢复。

Debian / Ubuntu(iptables-persistent)

# 安装
sudo apt install iptables-persistent

# 保存当前规则
sudo netfilter-persistent save

# 或手动保存
sudo iptables-save > /etc/iptables/rules.v4
sudo ip6tables-save > /etc/iptables/rules.v6

# 手动恢复
sudo iptables-restore < /etc/iptables/rules.v4
sudo ip6tables-restore < /etc/iptables/rules.v6

RHEL / CentOS(iptables-services)

# 保存规则
sudo service iptables save

# 或手动保存
sudo iptables-save > /etc/sysconfig/iptables

# 重新加载
sudo iptables-restore < /etc/sysconfig/iptables

通用方法(systemd 启动脚本)

# 创建一个 systemd oneshot 服务
sudo cat > /etc/systemd/system/iptables-restore.service << 'EOF'
[Unit]
Description=Restore iptables rules
Before=network-pre.target

[Service]
Type=oneshot
ExecStart=/sbin/iptables-restore /etc/iptables/rules.v4
ExecStart=/sbin/ip6tables-restore /etc/iptables/rules.v6
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl enable iptables-restore

查错与调试

# 查看规则计数器(判断包是否命中了某条规则)
iptables -L -n -v

# 实时监控匹配日志
tail -f /var/log/kern.log | grep IPTABLES-DROP

# 检查计数是否在增长
watch -n 1 'iptables -L INPUT -n -v'

# 临时完全放行(调试用)
iptables -P INPUT ACCEPT
iptables -P FORWARD ACCEPT
iptables -P OUTPUT ACCEPT
iptables -F

# 排查连接跟踪表
cat /proc/net/nf_conntrack | head

常见问题

Q:我执行 iptables 规则后 SSH 断了?

你将默认策略设为了 DROP,但没有先放行 SSH。

解决方法(通过 VPS 管理面板的 VNC/控制台):

# 先临时放行(如果还能操作)
iptables -P INPUT ACCEPT

# 或者让机房重启(如果设置了 iptables-restore 里有 SSH 规则)

预防措施: 永远先加 SSH 放行规则,再改默认策略;或使用 crontab 定时清空规则作为保险。

# crontab 保险:每 5 分钟清空防火墙(调试期间用)
*/5 * * * * /sbin/iptables -F

Q:iptables 和 iptables-legacy、iptables-nft 有什么区别?

  • iptables-legacy — 原始的 iptables,操作 ip_tables 内核模块
  • iptables-nft — 兼容层,语法一样但底层用 nf_tables 内核模块
  • 现代发行版默认 iptables → iptables-nft
# 查看
iptables --version
# iptables v1.8.7 (nf_tables)  ← 这是 nft 兼容模式
# iptables v1.4.21 (legacy)    ← 这是传统模式

Q:规则太多了,性能会变差吗?

会。iptables 是链式遍历,规则匹配完才停止。规则集很大时(数百条以上),建议:

  1. 将常用允许规则放在前面
  2. 使用 ipset 管理 IP 集合(而不是一条条写)
  3. 考虑迁移到 nftables(集合+映射性能更好)

Q:如何统计各规则的匹配次数?

iptables -L INPUT -n -v
# 第一列就是包计数,第二列是字节数
# 如果计数长时间不变,说明这条规则没匹配到

总结

操作 命令
查看 filter 表规则 iptables -L -n -v
查看 nat 表规则 iptables -t nat -L -n -v
允许端口 iptables -A INPUT -p tcp --dport 80 -j ACCEPT
拒绝 IP iptables -A INPUT -s 1.2.3.4 -j DROP
端口转发 iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to-destination 10.0.0.2:80
保存规则 iptables-save > /etc/iptables/rules.v4
恢复规则 iptables-restore < /etc/iptables/rules.v4
清空所有规则 iptables -F
修改默认策略 iptables -P INPUT DROP

最后的建议:如果你是新手,不要直接用 iptables 配置防火墙 —— 先试试 ufw。如果你在管理生产环境,建议逐步迁移到 nftables。iptables 虽然经典,但已经是"上一个时代"的技术了。