iptables 完全指南 / 第 01 章:Netfilter 架构与 iptables 历史
第 01 章:Netfilter 架构与 iptables 历史
本章目标:理解 Linux 数据包过滤的内核基础,掌握 iptables 的定位,了解 nftables 的演进方向。
1.1 Netfilter 框架概述
Netfilter 是 Linux 内核中的一个包过滤框架,它在内核网络协议栈的多个位置插入了钩子点(Hook Points),允许模块化的代码对经过的数据包进行检查、修改或丢弃。
1.1.1 Netfilter 的设计哲学
Netfilter 的核心设计理念是可扩展性。它不直接提供防火墙功能,而是提供一套基础设施:
用户态工具(iptables / nft)
│
▼
┌─────────────────────────────────────┐
│ Netfilter 框架 │
│ ┌──────────────────────────────┐ │
│ │ 钩子点 (Hook Points) │ │
│ │ ┌──────┐ ┌──────┐ ┌──────┐ │ │
│ │ │ PRER │ │FORWD│ │ POST │ │ │
│ │ │OUTING│ │ │ │ROUTNG│ │ │
│ │ └──────┘ └──────┘ └──────┘ │ │
│ │ ┌──────┐ ┌──────┐ │ │
│ │ │INPUT │ │OUTPUT│ │ │
│ │ └──────┘ └──────┘ │ │
│ └──────────────────────────────┘ │
│ ┌──────────────────────────────┐ │
│ │ 表 (Tables) │ │
│ │ raw → mangle → nat → filter │ │
│ └──────────────────────────────┘ │
└─────────────────────────────────────┘
│
▼
网络协议栈继续处理
1.1.2 五个钩子点
Netfilter 定义了五个标准钩子点,数据包在内核协议栈中流经这些点时,会触发注册在该钩子上的处理函数:
| 钩子点 | 触发时机 | 典型用途 |
|---|---|---|
NF_INET_PRE_ROUTING | 数据包进入路由决策之前 | DNAT、连接跟踪入口 |
NF_INET_LOCAL_IN | 数据包目的是本机 | INPUT 链过滤 |
NF_INET_FORWARD | 数据包需要转发 | FORWARD 链过滤 |
NF_INET_LOCAL_OUT | 本机产生的数据包 | OUTPUT 链过滤 |
NF_INET_POST_ROUTING | 数据包离开路由决策之后 | SNAT、MASQUERADE |
1.1.3 数据包流向图
┌─────────────────────────────────────────────┐
│ 本机进程 │
│ ┌──────────────┐ │
│ │ 应用程序 │ │
│ └──────┬───────┘ │
│ │ OUTPUT │
│ ▼ │
│ ┌──────────────┐ │
│ │ 路由决策 │ │
│ └──────┬───────┘ │
│ │ │
│ ▼ │
┌────────┐ ┌───────┴──────┐ ┌──────────────┐ ┌──────────┐ │
│ 网络 │────→│PRE_ROUTING │──→│ 路由决策 │──→│POST_ROUTING│─→│ 网络
│ 接口 │ └──────────────┘ └──────┬───────┘ └──────────┘ │ │ 接口
└────────┘ │ │
▼ │
┌──────────────┐ │
│ INPUT │ │
└──────┬───────┘ │
│ │
▼ │
┌──────────────┐ │
│ 本机进程 │ │
└──────────────┘ │
│
┌───────────────────────────────────────────┘
│
│ FORWARD(转发)
▼
┌──────────────┐
│ 路由决策 │──→ POST_ROUTING → 网络接口
└──────────────┘
关键理解:数据包的"命运"在路由决策那一刻确定——是发给本机(INPUT),还是转发给其他主机(FORWARD),还是由本机发出(OUTPUT)。
1.2 iptables 的历史演进
1.2.1 从 ipchains 到 iptables
| 时间 | 事件 | 说明 |
|---|---|---|
| 1995 年 | ipfwadm | Linux 2.0 时代的防火墙工具 |
| 1999 年 | ipchains | Linux 2.2,引入链的概念,但不支持有状态过滤 |
| 2000 年 | iptables | Linux 2.4,引入表的概念、有状态过滤、NAT |
| 2001 年 | Netfilter 子系统 | 正式并入内核主线 |
| 2008 年 | conntrack 改进 | 连接跟踪性能大幅优化 |
| 2014 年 | nftables | Linux 3.13,新一代包过滤框架进入内核 |
| 2018 年 | iptables 标记为 “legacy” | nftables 成为推荐方案 |
| 2020 年+ | 并存期 | 大多数发行版同时支持两者 |
1.2.2 iptables 的版本和变体
| 变体 | 说明 | 使用场景 |
|---|---|---|
iptables | 经典版本,操作 IPv4 | 传统服务器 |
ip6tables | 操作 IPv6 | IPv6 防火墙 |
arptables | 操作 ARP 协议 | ARP 过滤 |
ebtables | 操作以太网帧 | 桥接网络过滤 |
iptables-nft | nftables 后端 + iptables 语法 | 过渡期兼容 |
注意:在较新的发行版(如 Debian 10+、Ubuntu 20.04+、RHEL 8+)中,
iptables命令实际上是iptables-nft,底层使用 nftables 内核 API。
1.3 iptables vs nftables 对比
1.3.1 架构差异
iptables 架构:
┌─────────────────────────────────────────┐
│ iptables │ ip6tables │ arptables │ ebtables │ ← 用户态工具
├─────────────────────────────────────────┤
│ ip_tables │ ip6_tables │ arp_tables │ bridge │ ← 内核模块
├─────────────────────────────────────────┤
│ Netfilter 钩子 │
└─────────────────────────────────────────┘
nftables 架构:
┌─────────────────────────────────────────┐
│ nft 命令行工具 │ ← 统一用户态工具
├─────────────────────────────────────────┤
│ nf_tables 内核模块 │ ← 统一内核模块
├─────────────────────────────────────────┤
│ Netfilter 钩子 │
└─────────────────────────────────────────┘
1.3.2 功能对比
| 特性 | iptables | nftables |
|---|---|---|
| 内核模块数量 | 多个(ip_tables、iptable_filter 等) | 单一(nf_tables) |
| 规则匹配 | 线性扫描 | 支持集合(set)和字典 |
| 原子操作 | 不支持(需逐条操作) | 支持(整表替换) |
| 自定义链 | 有限支持 | 原生支持 |
| IPv4/IPv6 | 需要两套工具 | 统一处理 |
| 性能 | 规则多时性能下降明显 | 集合查找 O(1) |
| 语法 | 命令行参数 | 类编程语言语法 |
| 调试 | 有限 | 内置追踪功能 |
| 生态成熟度 | 非常成熟 | 快速成熟中 |
1.3.3 语法对比示例
iptables 语法:
# 允许 SSH 访问
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
# 允许已建立的连接
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
# 默认拒绝
iptables -P INPUT DROP
等价的 nftables 语法:
# 创建表和链
nft add table inet filter
nft add chain inet filter input { type filter hook input priority 0 \; policy drop \; }
# 允许已建立的连接
nft add rule inet filter input ct state established,related accept
# 允许 SSH 访问
nft add rule inet filter input tcp dport 22 accept
1.4 适用场景分析
1.4.1 iptables 适用场景
| 场景 | 说明 | 推荐度 |
|---|---|---|
| 传统服务器运维 | 现有规则体系成熟,文档丰富 | ⭐⭐⭐⭐⭐ |
| Docker/Kubernetes 环境 | 容器平台深度依赖 iptables | ⭐⭐⭐⭐⭐ |
| 嵌入式设备 | 内核较老,可能不支持 nftables | ⭐⭐⭐⭐ |
| 教学与学习 | 概念清晰,资料多 | ⭐⭐⭐⭐⭐ |
| 简单防火墙需求 | 规则少、逻辑简单 | ⭐⭐⭐⭐ |
1.4.2 nftables 适用场景
| 场景 | 说明 | 推荐度 |
|---|---|---|
| 新项目部署 | 从零开始,无历史包袱 | ⭐⭐⭐⭐⭐ |
| 大规模规则集 | 集合查找性能优势明显 | ⭐⭐⭐⭐⭐ |
| 多协议环境 | IPv4/IPv6 统一管理 | ⭐⭐⭐⭐⭐ |
| 复杂策略 | 需要编程式逻辑 | ⭐⭐⭐⭐ |
| 高频规则变更 | 原子操作,避免规则闪烁 | ⭐⭐⭐⭐⭐ |
1.4.3 企业场景:如何选择?
┌──────────────────┐
│ 是否有现有 iptables │
│ 规则需要维护? │
└────────┬─────────┘
是 │ │ 否
▼ ▼
┌──────────┐ ┌──────────────┐
│ 保持 │ │ 内核版本 ≥3.13?│
│ iptables │ └──────┬───────┘
└──────────┘ 是 │ │ 否
▼ ▼
┌────────┐ ┌──────────┐
│ 使用 │ │ 使用 │
│nftables│ │ iptables │
└────────┘ └──────────┘
实际建议:如果你的环境中有 Docker,短期内不要急于迁移到 nftables,因为 Docker 的网络驱动(如
docker0、br-xxx桥接)高度依赖 iptables 的nat和filter表。
1.5 Netfilter 内核模块体系
1.5.1 核心模块
| 模块 | 功能 |
|---|---|
nf_tables | nftables 核心框架 |
nf_tables_inet | nftables IPv4/IPv6 混合支持 |
ip_tables | iptables IPv4 核心 |
iptable_filter | filter 表实现 |
iptable_nat | nat 表实现 |
iptable_mangle | mangle 表实现 |
iptable_raw | raw 表实现 |
nf_conntrack | 连接跟踪核心 |
nf_conntrack_ftp | FTP 协议连接跟踪辅助 |
1.5.2 查看已加载模块
# 查看所有 Netfilter 相关模块
lsmod | grep -E "^(nf_|ipt_|xt_|ip6t_)"
# 典型输出示例:
# nf_conntrack 147456 4 xt_conntrack,nf_nat,nf_conntrack_netlink,xt_CHECKSUM
# nf_defrag_ipv6 16384 1 nf_conntrack
# nf_nat 40960 2 nf_nat_masquerade_ipv4,nf_nat_ipv4
# ip_tables 28672 3 iptable_filter,iptable_mangle,iptable_raw
# xt_conntrack 16384 2
# xt_tcpudp 16384 8
1.5.3 加载必要的内核模块
# 手动加载连接跟踪模块
modprobe nf_conntrack
modprobe nf_conntrack_ipv4
# 加载 NAT 相关模块
modprobe nf_nat
modprobe nf_nat_masquerade_ipv4
# 开机自动加载
echo "nf_conntrack" >> /etc/modules-load.d/conntrack.conf
echo "nf_nat" >> /etc/modules-load.d/nat.conf
1.6 动手实验:观察 Netfilter 钩子
实验 1:用 tcpdump 观察数据包流向
# 终端 1:监听所有接口的 ICMP 包
sudo tcpdump -i any icmp -n
# 终端 2:ping 一个外部地址
ping -c 1 8.8.8.8
实验 2:查看当前内核的 Netfilter 配置
# 查看内核是否支持 Netfilter
grep CONFIG_NETFILTER /boot/config-$(uname -r) | head -20
# 查看当前运行的 conntrack 参数
sysctl -a | grep net.netfilter.nf_conntrack
实验 3:用 iptables -L 查看初始状态
# 查看所有链(初始状态应该是空的)
sudo iptables -L -n -v
# 典型输出:
# Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
# pkts bytes target prot opt in out source destination
#
# Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
# pkts bytes target prot opt in out source destination
#
# Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
# pkts bytes target prot opt in out source destination
解读:默认策略是
ACCEPT,没有任何规则,所有数据包都被接受——这是一个完全开放的防火墙状态,生产环境必须加固。
1.7 注意事项
⚠️ 远程操作防火墙的风险:如果你通过 SSH 远程管理服务器,在添加
DROP策略前,务必先添加允许 SSH 的规则,否则会立即断开连接。
# ❌ 危险操作:直接设置默认 DROP(远程会话将断开)
iptables -P INPUT DROP
# ✅ 正确做法:先添加允许规则
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
iptables -P INPUT DROP
⚠️ 内核版本兼容性:某些高级功能(如
hashlimit、connlimit)需要较新的内核版本和对应的xt_*模块。在生产环境使用前,先在测试环境验证模块是否可用。
⚠️ 容器环境注意:Docker、Podman 等容器运行时会自动插入大量 iptables 规则,手动修改 iptables 可能导致容器网络异常。
1.8 扩展阅读
| 资源 | 链接 | 说明 |
|---|---|---|
| Netfilter 官方文档 | https://www.netfilter.org/documentation/ | 权威参考 |
| nftables Wiki | https://wiki.nftables.org/ | nftables 官方指南 |
| Linux 内核源码 - Netfilter | https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/net/netfilter | 内核实现 |
| 《Linux 防火墙》(第4版) | Michael Rash 著 | 经典教材 |
| Red Hat - 使用 iptables | https://docs.redhat.com/ | RHEL 官方文档 |
本章小结
| 要点 | 说明 |
|---|---|
| Netfilter | 内核包过滤框架,提供 5 个钩子点 |
| iptables | Netfilter 的用户态管理工具,2000 年诞生 |
| nftables | iptables 的继任者,2014 年进入内核 |
| 共存 | 当前两者并存,iptables 仍广泛使用 |
| 核心模块 | ip_tables、iptable_filter、nf_conntrack |
下一章:第 02 章:核心概念——四表五链,将深入讲解 iptables 的表、链、规则等核心概念。