| 年代 | 框架 | 特点 | 现状 |
|---|---|---|---|
| 2000 | iptables | 基于 netfilter 钩子,规则链遍历,O(n) 性能 | 维护模式,逐步废弃 |
| 2014 | nftables | 原生集成功能,规则集优化,O(1) 性能,统一 IPv4/IPv6 | 当前内核标准 |
| 2019+ | bpfilter | eBPF 驱动,用户态处理,极致性能 | 实验阶段,未普及 |
展开代码用户命令 │ ├──► ufw (Ubuntu) ──► iptables 语法 ──► iptables-nft ──► nftables 内核 │ ├──► firewalld (RHEL) ──► 直接生成 nftables 规则 ──► nftables 内核 │ └──► iptables 传统命令 ──► xtables-nft 兼容层 ──► nftables 内核
关键认知:现代 Linux 发行版(Ubuntu 22.04+、RHEL 8+、Debian 11+)内核已没有传统 iptables,所有 iptables 命令都通过 iptables-nft 翻译成 nftables 执行。
展开代码┌─────────────────────────────────────────┐ │ 用户层:ufw CLI │ │ ufw allow 22/tcp │ │ ufw deny from 10.0.0.100 │ └─────────────────┬───────────────────────┘ │ Python 解析 ▼ ┌─────────────────────────────────────────┐ │ 配置层:/lib/ufw/*.rules │ │ -A ufw-user-input -p tcp --dport 22 -j ACCEPT │ -A ufw-user-input -s 10.0.0.100 -j DROP └─────────────────┬───────────────────────┘ │ 调用 /usr/sbin/iptables ▼ ┌─────────────────────────────────────────┐ │ 翻译层:iptables-nft │ │ 将 iptables 语法转换为 nftables 对象: │ add rule ip filter ufw-user-input tcp dport 22 accept └─────────────────┬───────────────────────┘ │ netlink 套接字 ▼ ┌─────────────────────────────────────────┐ │ 内核层:nftables │ │ 真正的包过滤执行引擎 │ └─────────────────────────────────────────┘
| 文件 | 作用 | 修改建议 |
|---|---|---|
/etc/ufw/ufw.conf | 全局开关、日志级别 | 一般不动 |
/etc/ufw/before.rules | ufw 规则之前执行(如 NAT) | 高级自定义 |
/etc/ufw/after.rules | ufw 规则之后执行(如特殊日志) | 高级自定义 |
/etc/ufw/user.rules | 用户规则主文件(ufw 命令生成) | 手动编辑需谨慎 |
/etc/ufw/applications.d/ | 应用配置文件(如 OpenSSH、Nginx) | 可自定义服务名 |
展开代码# 单行放行,立即生效(无需 reload) sudo ufw allow 22/tcp # 多端口逗号分隔 sudo ufw allow 80,443/tcp # 整个区间(如被动模式 FTP) sudo ufw allow 1:65535/udp # 指定 IP + 端口 sudo ufw allow from 192.168.1.10 to any port 3306 # 查看生成的 nftables 规则 sudo nft list chain ip filter ufw-user-input # 输出: # chain ufw-user-input { # tcp dport 22 accept # tcp dport { 80, 443 } accept # udp dport 1-65535 accept # }
展开代码# 放行整个网段的所有端口(管理网) sudo ufw allow from 192.168.5.0/24 # 仅允许特定 IP 访问数据库 sudo ufw allow from 10.0.0.50 to any port 3306 proto tcp # 显式拒绝(优先级高于 allow,日志记录) sudo ufw deny from 10.0.0.100 # 插入到特定位置(第 3 条规则) sudo ufw insert 3 allow from 172.16.0.0/12
展开代码# SSH 防暴力:30 秒内≥6 次连接,后续 DROP sudo ufw limit 22/tcp # 自定义 HTTP API 限速 sudo ufw limit 8080/tcp # 查看生成的 limit 规则 sudo nft list chain ip filter ufw-user-limit # 输出: # chain ufw-user-limit { # limit rate 6/minute burst 5 packets accept # log prefix "[UFW LIMIT BLOCK] " level 4 # drop # }
原理说明:limit 使用 nftables 的 meter 对象,基于令牌桶算法,比传统 fail2ban 更轻量。
展开代码# 外网主动进入全丢弃(最安全的默认) sudo ufw default deny incoming # 本机出站全放行(通常如此) sudo ufw default allow outgoing # 转发包拒绝并回 ICMP(禁止当路由器) sudo ufw default reject routed # 启用防火墙(首次会提示可能断开 SSH,确认 y) sudo ufw enable # 开机自启 sudo systemctl enable ufw # 完全禁用(清空所有规则) sudo ufw disable
展开代码# 查看带编号的规则列表 sudo ufw status numbered # 删除第 5 条规则 sudo ufw delete 5 # 删除特定规则(需完全匹配) sudo ufw delete allow from 192.168.5.0/24 # 重置为初始状态(危险!) sudo ufw reset
展开代码# 启用日志(默认 low,只记录被阻止的新连接) sudo ufw logging on # 详细日志(记录所有匹配,慎用,磁盘压力大) sudo ufw logging high # 关闭日志 sudo ufw logging off # 实时查看 UFW 日志 sudo journalctl -k -f | grep UFW # 或 sudo tail -f /var/log/ufw.log
展开代码# 创建自定义服务定义 sudo tee /etc/ufw/applications.d/custom-app <<'EOF' [CustomApp] title=My Custom Application description=This is a custom service running on port 8080 and 8443 ports=8080,8443/tcp EOF # 使用应用名放行 sudo ufw allow 'CustomApp' # 查看所有应用 sudo ufw app list
Docker 默认绕过 ufw,直接操作 iptables。解决方案:
展开代码# 方案 1:修改 Docker 默认行为 sudo tee /etc/docker/daemon.json <<'EOF' { "iptables": false } EOF sudo systemctl restart docker # 然后手动用 ufw 放行 Docker 端口 # 方案 2:使用 ufw-docker 工具 sudo wget -O /usr/local/bin/ufw-docker https://github.com/chaifeng/ufw-docker/raw/master/ufw-docker sudo chmod +x /usr/local/bin/ufw-docker sudo ufw-docker install
firewalld 与 ufw 的最大区别:firewalld 直接生成 nftables 规则,跳过 iptables 翻译层,且支持 动态区域(zone) 和 运行时/永久配置分离。
展开代码┌─────────────────────────────────────────┐ │ 用户层:firewall-cmd │ │ firewall-cmd --add-port=3000/tcp │ │ firewall-cmd --reload │ └─────────────────┬───────────────────────┘ │ D-Bus 调用 ▼ ┌─────────────────────────────────────────┐ │ 守护进程:firewalld │ │ - 解析 XML 配置 │ │ - 管理 zone、service、rich rules │ │ - 直接生成 nftables 规则 │ └─────────────────┬───────────────────────┘ │ netlink 套接字 ▼ ┌─────────────────────────────────────────┐ │ 内核层:nftables │ │ 真正的包过滤执行引擎 │ └─────────────────────────────────────────┘
| Zone | 信任度 | 默认用途 |
|---|---|---|
drop | 最低 | 丢弃所有进入,无响应 |
block | 极低 | 拒绝进入,回 ICMP |
public | 低 | 公共 Wi-Fi,仅放行 SSH/DHCP |
external | 中 | 对外路由器,启用 NAT |
internal | 中高 | 内网,放行更多服务 |
trusted | 最高 | 完全信任,放行所有 |
展开代码# 仅运行时生效(重启丢失) sudo firewall-cmd --add-port=3000/tcp # 永久生效(写入 XML,需 reload) sudo firewall-cmd --permanent --add-port=3000/tcp sudo firewall-cmd --reload # 多端口 sudo firewall-cmd --permanent --add-port={8080,8443}/tcp # 范围端口 sudo firewall-cmd --permanent --add-port=60000-61000/tcp
关键区别:--permanent 只修改配置文件,必须 reload 才生效;这是 firewalld 与 ufw 的最大 UX 差异。
firewalld 的富规则比 ufw 更强大,支持 优先级、时间限制、日志级别:
展开代码# 整网段放行任何端口 sudo firewall-cmd --permanent \ --add-rich-rule='rule family="ipv4" source address=192.168.10.0/24 accept' # 仅允许特定 IP 访问 MySQL sudo firewall-cmd --permanent \ --add-rich-rule='rule family="ipv4" source address=10.0.0.50 port port=3306 protocol=tcp accept' # 拒绝恶意 IP(带日志) sudo firewall-cmd --permanent \ --add-rich-rule='rule family="ipv4" source address=192.168.66.100 log prefix="DROP: " level="notice" drop' # 时间限制(工作时间放行) sudo firewall-cmd --permanent \ --add-rich-rule='rule family="ipv4" source address=10.0.0.0/24 service name=ssh accept limit value="2/m"'
展开代码# 防暴力破解:30 秒内≥6 次连接 3000/tcp,DROP sudo firewall-cmd --permanent \ --add-rich-rule='rule family="ipv4" port port=3000 protocol=tcp limit value="6/m" accept' # 查看生成的 nftables 规则 sudo nft list chain inet firewalld filter_IN_public_allow
展开代码# 查看预定义服务 sudo firewall-cmd --get-services # 输出:ssh dhcpv6-client http https mysql postgresql ... # 放行服务(比端口更语义化) sudo firewall-cmd --permanent --add-service=http sudo firewall-cmd --permanent --add-service=https # 自定义服务 sudo tee /etc/firewalld/services/custom-app.xml <<'EOF' <?xml version="1.0" encoding="utf-8"?> <service> <short>Custom App</short> <description>My application on 8080 and 8443</description> <port protocol="tcp" port="8080"/> <port protocol="tcp" port="8443"/> </service> EOF sudo firewall-cmd --reload sudo firewall-cmd --permanent --add-service=custom-app
展开代码# 查看当前生效配置 sudo firewall-cmd --list-all # 输出解析见下方 # 修改默认区域 sudo firewall-cmd --set-default-zone=drop # 网卡绑定到特定区域 sudo firewall-cmd --permanent --zone=internal --change-interface=eth1 # 修改区域默认动作 sudo firewall-cmd --permanent --zone=public --set-target=DROP
--list-all 输出详解:
展开代码public (active) # 当前生效的区域名称 target: default # 默认动作:default/ACCEPT/DROP/REJECT icmp-block-inversion: no # ICMP 是否反向阻止 interfaces: ens18 # 绑定的网卡 sources: # 源地址白名单/黑名单 services: ssh dhcpv6-client http # 放行的服务 ports: 3000/tcp 8080-8090/udp # 单独放行的端口 protocols: # 放行的协议(如 gre) forward: yes # 是否允许 IP 转发 masquerade: no # 是否启用 SNAT(源地址转换) forward-ports: # 端口转发(DNAT) source-ports: # 源端口限制 icmp-blocks: # 阻止的 ICMP 类型 rich rules: # 富规则列表(按优先级) rule family="ipv4" source address=192.168.10.0/24 accept rule family="ipv4" source address=10.0.0.100 drop
展开代码# 记录所有被拒绝的包 sudo firewall-cmd --set-log-denied=all # 仅记录特定区域 sudo firewall-cmd --zone=public --set-log-denied=unicast # 关闭日志 sudo firewall-cmd --set-log-denied=off # 实时查看 sudo journalctl -k -f | grep -E "REJECT|DROP"
展开代码# 停止服务 sudo systemctl stop firewalld # 清空所有配置 sudo rm -rf /etc/firewalld/zones/* sudo rm -rf /etc/firewalld/services/custom-* # 恢复默认并重启 sudo firewall-cmd --reset-to-defaults sudo systemctl start firewalld
| 维度 | ufw | firewalld |
|---|---|---|
| 设计目标 | 极简、快速上手 | 企业级、动态管理 |
| 默认发行版 | Ubuntu、Debian | RHEL、CentOS、Fedora、SUSE |
| 配置语法 | 类英文(allow 22/tcp) | 参数式(--add-port=22/tcp) |
| 生效方式 | 立即生效 | 运行时立即,永久需 reload |
| 底层路径 | ufw → iptables → nftables | firewalld → 直接 nftables |
| 区域概念 | ❌ 无 | ✅ 多 zone,动态切换 |
| 运行时/永久分离 | ❌ 无(所有规则立即持久化) | ✅ 明确分离,安全测试 |
| 富规则能力 | 基础(IP、端口、limit) | 强大(时间、优先级、日志、icmp) |
| 服务抽象 | 简单(applications.d) | 完善(XML 定义,内置 100+) |
| IPv6 支持 | 自动,同规则 | 自动,同规则 |
| NAT/端口转发 | 需手动编辑 before.rules | 原生支持(--add-forward-port) |
| 与 Docker 集成 | 冲突较多 | 相对友好 |
| 学习曲线 | 平缓 | 陡峭但功能更强 |
| 场景 | 推荐 | 理由 |
|---|---|---|
| 个人服务器/VPS | ufw | 三条命令搞定,不折腾 |
| Ubuntu 云主机 | ufw | 官方支持,文档丰富 |
| RHEL/CentOS 企业环境 | firewalld | SELinux 集成,审计合规 |
| 需要动态区域切换 | firewalld | zone 机制,网络环境变化自动适配 |
| 复杂 NAT/端口转发 | firewalld | 原生支持,无需手写规则 |
| 容器化环境(K8s) | 直接 nftables 或 Cilium | 绕过用户层工具,性能最优 |
展开代码# 查看 ufw 生成的 nftables 规则 sudo nft list ruleset | grep -A20 "chain ufw-user-input" # 查看 firewalld 生成的 nftables 规则 sudo nft list ruleset | grep -A20 "chain filter_IN_public" # 完整规则集 sudo nft list ruleset > /tmp/nftables-rules.txt
展开代码# 创建表和链 sudo nft add table inet my_filter sudo nft add chain inet my_filter my_input { type filter hook input priority 0 \; policy drop \; } # 添加规则 sudo nft add rule inet my_filter my_input tcp dport 22 accept sudo nft add rule inet my_filter my_input ip saddr 192.168.1.0/24 accept # 查看 sudo nft list table inet my_filter
| 现象 | 排查命令 | 解决 |
|---|---|---|
| 规则不生效 | sudo nft list ruleset | 检查是否有 DROP 在前 |
| ufw 启动失败 | sudo ufw status verbose | 检查 before.rules 语法 |
| firewalld reload 报错 | sudo firewall-cmd --check-config | 检查 XML 语法 |
| Docker 端口绕过防火墙 | sudo iptables -t nat -L -n | 禁用 Docker iptables 或 ufw-docker |
| 日志不记录 | `sudo dmesg | grep -i nft` |
| 连接数暴涨 | sudo ss -s / `sudo conntrack -L | wc -l` |
本文作者:zzz
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!