Skip to content

iptables防火墙

iptables 在 Linux 上用于主机侧的包过滤和 NAT。虽然新发行版逐渐向 nftables 迁移,但 iptables 仍然广泛应用在老系统、容器网络和各类技术文档中。

一、iptables 和 firewalld 的关系

RHEL/CentOS 上常见 firewalld,它的底层可以调用 iptables 或 nftables。如果 firewalld 正在管理规则,直接手动改 iptables 规则可能被 firewalld 覆盖。处理防火墙之前先确认谁在主控。

bash
iptables -V                   # 看 iptables 版本
systemctl status firewalld    # 看 firewalld 是否在运行
iptables -L -n -v             # 看当前 iptables filter 表规则

iptables 是用户态管理工具,真正在内核里处理报文的是 netfilter 框架。命令只是把规则写入内核,数据包的匹配和动作在内核完成。

二、表、链和规则

iptables 的规则体系分三个层次理解:

概念说明
表(Table)按功能分类的规则集合:过滤、NAT、修改报文
链(Chain)报文经过内核网络栈时的检查点
规则(Rule)匹配条件 + 动作,按顺序逐条比对

四张常用表:

功能典型场景
filter过滤,决定要不要让包通过开放/阻止端口,最常用
nat地址转换源地址转换(SNAT/MASQUERADE)、目标地址转换(DNAT)
mangle修改报文头修改 TOS、TTL,较少直接使用
raw在连接跟踪之前处理排除特定流量不做状态跟踪

五条链对应报文经过内核的不同位置:

触发时机
PREROUTING报文刚到达网卡,尚未路由决策
INPUT经过路由决策后,确定目标是本机
FORWARD经过路由决策后,确定目标是另一台机器(本机作为网关)
OUTPUT本机进程发出的报文
POSTROUTING报文即将离开网卡(路由决策之后)

报文经过的路径取决于流量方向:

流量方向经过的链
外部 → 本机服务PREROUTING → INPUT
本机 → 外部OUTPUT → POSTROUTING
外部 → 本机转发 → 外部PREROUTING → FORWARD → POSTROUTING

开放端口的场景主要看 filter 表的 INPUT 链。排查端口不通时,先判流量的方向(进本机、出本机、还是转发),就知道该看 INPUT、OUTPUT 还是 FORWARD。

三、查看规则

bash
iptables -L -n -v                # 默认 filter 表,-n 不解析名称,-v 显示计数器
iptables -S                      # 以接近命令的形式输出(方便复制和回滚)
iptables -t nat -L -n -v         # 查看 nat 表
iptables -L INPUT -n --line-numbers   # 带行号,方便后续按行号删除

iptables -S 的输出格式可以直接当作命令重新执行,回滚和备份时更实用。-v 输出中的计数器(pkts、bytes 列)也很重要——某条规则的计数器一直不涨,说明包没有匹配到这里。

四、规则基本结构

一条规则由匹配条件和动作组成:

组成示例含义
操作-A INPUT追加(Append)到 INPUT 链末尾
协议-p tcp只匹配 TCP 协议
目标端口--dport 22目标端口是 22
状态-m state --state ESTABLISHED,RELATED连接状态为已建立或相关
动作-j ACCEPT匹配后放行

规则的顺序至关重要:iptables 从链的第一条开始逐条向下匹配,命中即执行动作,不再继续往下看。

一个安全的最小规则集:

bash
# 放行已经建立和相关的连接——保证现有 SSH 不会断
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

# 放行本机回环(lo),很多本地服务依赖 127.0.0.1 通信
iptables -A INPUT -i lo -j ACCEPT

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

# 放行业务端口
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT

# 默认策略:INPUT 链未匹配的包一律丢弃
iptables -P INPUT DROP

远程操作防火墙时,默认策略(-P INPUT DROP)必须在放行 SSH 和相关连接的规则之后才设置。先在旁边留一个已登录的 tmux 会话更稳。

三种动作的区别:

动作行为对方看到的效果
ACCEPT放行正常通信
DROP直接丢弃,不回复任何内容超时(等待后无响应)
REJECT丢弃并回复错误(ICMP port unreachable 或 TCP RST)立即收到拒绝

公网入口常用 DROP(不暴露服务存在信息)。内网排错时 REJECT 更友好——失败快,不至于一直等超时。

五、状态跟踪

iptables 可以通过连接跟踪(conntrack)识别包属于哪个连接。

连接状态:

状态含义
NEW新发起的连接的第一个包
ESTABLISHED属于已有连接的包(双向)
RELATED与已有连接相关的包(如 FTP 的数据通道)
INVALID无法归类或异常的包

ESTABLISHED,RELATED 规则的核心价值:允许本机主动访问外部后,外部返回的响应包能够通过防火墙进来。如果没有这条规则,默认 DROP 的机器连自己主动发起的 HTTP 请求的回包都收不到。

部分新系统推荐 conntrack 模块写法:

bash
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

stateconntrack 底层都是 netfilter 的连接跟踪系统。conntrack 是更现代的模块,功能上基本等价。维护老机器时不用强行修改风格,新规则优先用 conntrack

六、规则的插入和删除

插入到指定位置:

bash
iptables -I INPUT 1 -p tcp --dport 22 -j ACCEPT   # 插入到 INPUT 链第 1 条

按行号删除:

bash
iptables -L INPUT -n --line-numbers         # 先看行号
iptables -D INPUT 3                         # 删除第 3 条

按规则内容匹配删除:

bash
iptables -D INPUT -p tcp --dport 80 -j ACCEPT

按行号删之前再看一遍行号。链中增删规则后,后续规则的编号会跟着变。

七、NAT

NAT 修改报文中的 IP 地址或端口。常见两类用法:

类型用途常用链
SNAT / MASQUERADE内网多台机器共享一个外网 IP 上网POSTROUTING
DNAT将外网的请求转发到内网某台机器PREROUTING

内网机器共享上网(MASQUERADE 自动使用出口网卡的 IP):

bash
iptables -t nat -A POSTROUTING -s 10.0.0.0/24 -o eth0 -j MASQUERADE

端口转发(外部访问本机 8080 转到内网 10.0.0.10:80):

bash
iptables -t nat -A PREROUTING -p tcp --dport 8080 -j DNAT --to-destination 10.0.0.10:80

做 NAT 转发时需要启用 IP 转发功能:

bash
sysctl -w net.ipv4.ip_forward=1

持久化:

bash
echo "net.ipv4.ip_forward = 1" > /etc/sysctl.d/99-ip-forward.conf
sysctl --system

排查 NAT 规则时,同时看 nat 表和 filter 表。DNAT 之后,后续链(如 FORWARD)看到的包已经是被改写过的——源端口 :8080 已经变成了 :80

八、保存和恢复规则

iptables 规则存在内存中,重启后丢失。不同发行版持久化方式不同:

RHEL/CentOS:

bash
service iptables save                 # 保存到 /etc/sysconfig/iptables
iptables-save > /etc/sysconfig/iptables

Debian/Ubuntu:

bash
apt install iptables-persistent -y
iptables-save > /etc/iptables/rules.v4

临时加规则救火后,马上确认持久化,否则下次重启规则丢失。

九、和 firewalld 共存时的注意点

bash
firewall-cmd --state
firewall-cmd --list-all
firewall-cmd --add-port=80/tcp --permanent
firewall-cmd --reload

如果团队统一用 firewalld 管理防火墙,不建议绕过它直接写 iptables。混着改的结果是规则互相覆盖,出问题时很难追溯规则的最终来源。

十、端口不通时的排查清单

bash
ss -lntp | grep ':80'                                 # 服务是否在监听
iptables -L INPUT -n -v --line-numbers                 # filter 表 INPUT 链规则和计数器
iptables -t nat -L -n -v --line-numbers                # NAT 表规则(有端口转发时)

看计数器——如果某条规则的计数器始终为 0,说明包没有匹配到这儿。方向、表、链或上游网络都可能有问题。