前言
Linux 防火墙经历了 iptables → nftables → firewalld(前端)的演进。现代 RHEL 系默认 firewalld(底层实为 nftables),但老机器和容器网络里 iptables 依旧无处不在。两个都要会。
一、先搞清三层"墙"
外部流量
│
▼ ① 云安全组(腾讯云/阿里云控制台, 机器之外)
│
▼ ② 系统防火墙(firewalld/iptables, 机器之内)
│
▼ ③ 应用自身监听(0.0.0.0 vs 127.0.0.1)
排查口子问题:从外到内逐层验证——安全组放了吗 → 系统防火墙放了吗 → 进程监听对吗。
二、firewalld:zone 思维
firewalld 把规则按 zone(区域) 组织,每个网卡绑定一个 zone:
firewall-cmd --get-default-zone # 默认 public
firewall-cmd --get-active-zones # 网卡与 zone 绑定关系
firewall-cmd --list-all # 当前 zone 全部规则
firewall-cmd --get-zones # 所有可用 zone
| zone | 语义 |
|---|---|
| public | 公共区域,只放行指定服务(服务器默认) |
| trusted | 全放行 |
| internal/drop/block | 内网/全拒/拒绝带响应 |
服务与端口操作:
# 放行标准服务(本质是 /usr/lib/firewalld/services/*.xml 里定义的端口组)
firewall-cmd --add-service=http --permanent
firewall-cmd --add-service=https --permanent
# 放行自定义端口
firewall-cmd --add-port=8080/tcp --permanent
firewall-cmd --add-port=60000-61000/udp --permanent
# 端口转发(本机 80 -> 8080)
firewall-cmd --add-forward-port=port=80:proto=tcp:toport=8080 --permanent
# 任何 --permanent 的修改都要 reload 生效
firewall-cmd --reload
# 注意: 不加 --permanent 只对运行时生效(重启丢失); 调试时可先运行时放行
富规则:精细控制
# 只允许特定网段访问 SSH
firewall-cmd --permanent --add-rich-rule='
rule family=ipv4 source address=10.0.0.0/24 port port=22 protocol=tcp accept'
# 封禁一个恶意 IP
firewall-cmd --permanent --add-rich-rule='
rule family=ipv4 source address=1.2.3.4 reject'
# 允许 ping
firewall-cmd --permanent --add-rich-rule='rule protocol value=icmp accept'
# 端口转发到另一台机器(需配 masquerade)
firewall-cmd --permanent --add-masquerade
firewall-cmd --permanent --add-rich-rule='
rule family=ipv4 forward-port port=443 protocol=tcp to-addr=10.0.1.20'
firewall-cmd --reload
三、iptables:表与链的世界
四表(处理优先级从高到低):raw → mangle → nat → filter
五链(规则挂载点):
PREROUTING ──► FORWARD ──► POSTROUTING (转发路径, nat 表主场)
│
▼
INPUT ──► [本机进程] ──► OUTPUT (本机进出, filter 表主场)
| 链 | 时机 |
|---|---|
| PREROUTING | 刚进网卡(DNAT 在这) |
| INPUT | 发给本机进程 |
| FORWARD | 经过本机转发(路由器/网关场景) |
| OUTPUT | 本机进程发出 |
| POSTROUTING | 即将发出网卡(SNAT 在这) |
规则 = 匹配条件 + 动作:
# 查看(-n 不解析域名, -v 带计数)
iptables -L INPUT -n -v --line-numbers
# 放行 80
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
# 只允许内网访问 22
iptables -A INPUT -p tcp -s 10.0.0.0/24 --dport 22 -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -j DROP # 其余全拒(规则从上到下匹配!)
# 封 IP
iptables -I INPUT -s 1.2.3.4 -j DROP # -I 插到最前(优先级最高)
# 删除第 3 条规则
iptables -D INPUT 3
# 已建立连接的回包放行(状态防火墙精髓)
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# 允许本机回环
iptables -A INPUT -i lo -j ACCEPT
动作速记:ACCEPT 放行 / DROP 丢弃(无响应)/ REJECT 拒绝(回拒绝报文)。
NAT 实战(做一台小路由器/网关):
# 开启转发
echo 1 > /proc/sys/net/ipv4/ip_forward
# SNAT: 内网 10.0.0.0/24 出公网(网卡 eth0 的 IP)
iptables -t nat -A POSTROUTING -s 10.0.0.0/24 -o eth0 -j MASQUERADE
# DNAT: 公网访问本机 8443 转给内网机器 443
iptables -t nat -A PREROUTING -p tcp --dport 8443 -j DNAT --to-destination 10.0.1.20:443
MASQUERADE是动态版 SNAT(出口 IP 会变时用,如拨号/DHCP)。
四、保存与持久化
# iptables 规则默认重启即失
iptables-save > /etc/sysconfig/iptables # RHEL 系保存
iptables-restore < /etc/sysconfig/iptables # 恢复
# firewalld 自动持久(--permanent 写入 /etc/firewalld/zones/)
ls /etc/firewalld/zones/
五、firewalld vs iptables vs nftables
| firewalld | iptables | nftables | |
|---|---|---|---|
| 定位 | 管理前端(规则易读易管理) | 经典工具 | 内核新框架(iptables 继任者) |
| 规则修改 | 增量(reload 不断连接) | 全量替换 | 增量 |
| 适合 | 日常服务器运维 | 老系统/精确控制/K8s 网络底层 | 新项目/高性能场景 |
Docker/K8s(kube-proxy iptables 模式)会直接操作 iptables 规则——这就是装了 Docker 后
iptables -L多出一堆链的原因,别手删。
六、排障速查
# 端口到底谁没放行?
# 1. 计数器证据: 每条规则有 pkts 计数, 看是否命中
iptables -L INPUT -nv | grep 8080
# 2. 抓包确认包到了没
tcpdump -i any -nn port 8080 -c 10
# 3. firewalld panic 模式(全断! 误开排查)
firewall-cmd --query-panic
# 4. 规则对了还不通: 检查内核转发与安全组
sysctl net.ipv4.ip_forward
小结
| 任务 | 命令 |
|---|---|
| 放行端口 | firewall-cmd --add-port=8080/tcp --permanent && firewall-cmd --reload |
| 白名单 | rich rule + source address= |
| 封 IP | rich rule reject 或 iptables -I INPUT -s x -j DROP |
| NAT 上网 | MASQUERADE + ip_forward |
| 排障 | 规则计数器 + tcpdump + 别忘安全组 |
本文是「Linux 运维」系列第 7 篇。