深入理解iptables:原理、逻辑与实战笔记

iptables是Linux内核中netfilter子系统的用户空间管理工具,是Linux系统上最强大、最灵活的防火墙解决方案之一。理解其工作原理和逻辑对于任何Linux系统管理员或网络工程师都至关重要。本笔记旨在从基础概念到实战操作,为你提供一个清晰的学习路径。


一、核心概念:四表五链

iptables的逻辑是围绕“表(Tables)”和“链(Chains)”构建的。数据包在内核中的网络协议栈中流动时,会经过这些表和链,iptables则在这些关键节点上设置规则(Rules)来决定数据包的命运。

1. 表(Tables)

表定义了规则的类型和处理时机。iptables主要有四个核心表:

  • filter 表 (默认表):这是最常用的表,负责“过滤”数据包。它决定了数据包是允许通过(ACCEPT)、拒绝(REJECT)还是丢弃(DROP)。

    • 主要用于:防火墙的访问控制。
  • nat 表 (Network Address Translation):用于修改数据包的源地址或目标地址,实现网络地址转换。

    • 主要用于:共享上网(SNAT/MASQUERADE)、端口转发(DNAT/REDIRECT)。
  • mangle:用于修改数据包的IP头信息,如服务类型(TOS)、生存时间(TTL)等。这是一个高级功能的表。

    • 主要用于:流量整形、策略路由。
  • raw:用于处理异常数据包,可以对数据包打上“NOTRACK”标记,使其跳过nat表和连接跟踪系统。

    • 主要用于:优化性能,处理大量连接的场景。

2. 链(Chains)

链是数据包在特定表中流经的一系列规则的集合。链分为内置链和自定义链。内置链与netfilter框架的钩子(Hooks)相关联,代表了数据包处理的关键节点。

filter 表中的内置链:

  • INPUT:处理目标地址是本机的数据包(入站流量)。
  • OUTPUT:处理由本机产生的数据包(出站流量)。
  • FORWARD:处理流经本机,但目标地址不是本机的数据包(转发流量)。

nat 表中的内置链:

  • PREROUTING:在数据包进入路由决策之前修改目标地址(DNAT)。
  • POSTROUTING:在数据包离开本机,完成路由决策之后修改源地址(SNAT)。
  • OUTPUT:修改本机产生的出站数据包的地址。

3. 规则(Rules)

规则是链中的一个条目,它定义了“如果数据包匹配这个条件,就执行这个动作”。一条规则包含两个核心部分:

  • 匹配器(Matchers):定义了匹配数据包的条件。可以是通用的(如源/目标IP、协议类型、端口号),也可以是扩展的(如连接状态、MAC地址等)。
  • 目标(Target):定义了匹配成功后要执行的动作。常见的Target有:
    • ACCEPT:允许数据包通过。
    • DROP:直接丢弃数据包,不给任何回应。
    • REJECT:拒绝数据包,并返回一个错误信息(如port-unreachable)。
    • LOG:记录数据包信息到系统日志,然后将数据包传递给链中的下一条规则。
    • SNAT:源地址转换,用于nat表的POSTROUTING链。
    • DNAT:目标地址转换,用于nat表的PREROUTING链。
    • MASQUERADE:动态的SNAT,适用于源IP是动态分配的场景(如PPPoE拨号)。

二、数据包处理流程

理解数据包如何在iptables的表和链中穿行是掌握iptables的关键。

  1. 入站流量(目标是本机)
    PREROUTING (raw -> mangle -> nat) -> INPUT (mangle -> filter) -> 本机应用

  2. 出站流量(由本机产生)
    本机应用 -> OUTPUT (raw -> mangle -> nat -> filter) -> POSTROUTING (mangle -> nat) -> 发出

  3. 转发流量(流经本机)
    PREROUTING (raw -> mangle -> nat) -> FORWARD (mangle -> filter) -> POSTROUTING (mangle -> nat) -> 发出

关键点

  • 数据包按顺序通过链中的规则,一旦匹配成功并执行了ACCEPTDROP等终结性Target,就不会再继续匹配链中的后续规则。
  • 每个链都有一个默认策略(Policy),如果数据包没有匹配链中的任何规则,将执行默认策略。默认策略通常是ACCEPTDROP

三、常用操作命令

iptables命令的基本语法是 iptables [-t table] -COMMAND chain [conditions] [-j target]

1. 查看规则

  • 查看指定表的所有规则(-L)
    1
    2
    3
    4
    5
    6
    7
    8
    # 查看filter表(默认)的规则,-v显示详细信息,-n使用数字格式显示IP和端口
    sudo iptables -L -v -n

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

    # 显示规则编号,方便删除
    sudo iptables -L --line-numbers

2. 添加规则

  • 追加规则到链尾(-A)

    1
    2
    # 允许来自192.168.1.100的SSH连接
    sudo iptables -A INPUT -p tcp -s 192.168.1.100 --dport 22 -j ACCEPT
  • 插入规则到链首或指定位置(-I)

    1
    2
    # 在INPUT链的第一个位置插入规则,允许所有本地回环接口的流量
    sudo iptables -I INPUT 1 -i lo -j ACCEPT

3. 删除规则

  • 按规则内容删除(-D)

    1
    2
    # 删除之前添加的SSH规则
    sudo iptables -D INPUT -p tcp -s 192.168.1.100 --dport 22 -j ACCEPT
  • 按规则编号删除(-D)

    1
    2
    3
    4
    # 先查看编号
    sudo iptables -L INPUT --line-numbers
    # 删除INPUT链的第3条规则
    sudo iptables -D INPUT 3

4. 清空与重置

  • 清空所有规则(-F, Flush)

    1
    2
    3
    4
    5
    # 清空filter表的所有规则
    sudo iptables -F

    # 清空nat表的所有规则
    sudo iptables -t nat -F
  • 删除所有自定义链(-X, Delete Chain)

    1
    2
    # 删除所有非内置的自定义链
    sudo iptables -X
  • 设置默认策略(-P, Policy)

    警告:在设置默认策略为DROP之前,请务必先添加允许SSH等关键连接的规则,否则可能导致服务器失联!

    1
    2
    3
    4
    5
    6
    7
    8
    # 设置INPUT链的默认策略为DROP
    sudo iptables -P INPUT DROP

    # 设置FORWARD链的默认策略为DROP
    sudo iptables -P FORWARD DROP

    # 通常OUTPUT链保持ACCEPT
    sudo iptables -P OUTPUT ACCEPT

5. 保存与恢复规则

iptables规则在系统重启后会丢失。要使其持久化:

  • 使用 iptables-saveiptables-restore

    1
    2
    3
    4
    5
    # 保存当前规则到文件
    sudo iptables-save > /etc/iptables/rules.v4

    # 从文件恢复规则
    sudo iptables-restore < /etc/iptables/rules.v4
  • 使用 iptables-persistent 包 (Debian/Ubuntu)

    1
    2
    3
    4
    5
    6
    # 安装
    sudo apt-get install iptables-persistent

    # 安装过程中会提示是否保存当前IPv4和IPv6规则
    # 手动保存
    sudo netfilter-persistent save

四、实战案例

案例1:基础服务器安全策略

目标:只允许SSH(22), HTTP(80), HTTPS(443)端口的入站连接,其他全部拒绝。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 1. 清空现有规则
sudo iptables -F
sudo iptables -X

# 2. 设置默认策略为DROP(安全第一)
sudo iptables -P INPUT DROP
sudo iptables -P FORWARD DROP
sudo iptables -P OUTPUT ACCEPT

# 3. 允许已建立的连接和相关连接(非常重要,否则连接会中断)
sudo iptables -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT

# 4. 允许本地回环接口
sudo iptables -A INPUT -i lo -j ACCEPT

# 5. 开放指定端口
sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT # SSH
sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT # HTTP
sudo iptables -A INPUT -p tcp --dport 443 -j ACCEPT # HTTPS

# 6. (可选) 允许ICMP (ping)
sudo iptables -A INPUT -p icmp --icmp-type 8 -j ACCEPT

# 7. 保存规则
sudo iptables-save | sudo tee /etc/iptables/rules.v4

案例2:端口转发(DNAT)

目标:将服务器的8080端口收到的流量转发到内网192.168.1.10机器的80端口。

1
2
3
4
5
6
7
8
9
# 1. 开启内核的IP转发功能
echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward

# 2. 在nat表的PREROUTING链添加DNAT规则
# -d 指定服务器公网IP
sudo iptables -t nat -A PREROUTING -p tcp -d <服务器公网IP> --dport 8080 -j DNAT --to-destination 192.168.1.10:80

# 3. 在filter表的FORWARD链允许该转发流量
sudo iptables -A FORWARD -p tcp -d 192.168.1.10 --dport 80 -j ACCEPT

案例3:共享上网(SNAT/MASQUERADE)

目标:让192.168.1.0/24网段的内网机器通过本服务器(假设公网网卡为eth0)上网。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 1. 开启内核的IP转发功能
echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward

# 2. 在nat表的POSTROUTING链添加地址伪装规则
# MASQUERADE适用于公网IP是动态变化的场景
sudo iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth0 -j MASQUERADE

# 如果公网IP是固定的,使用SNAT效率更高
# sudo iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth0 -j SNAT --to-source <你的固定公网IP>

# 3. 在filter表的FORWARD链允许内网到外网的流量
# 同样需要允许已建立的连接返回
sudo iptables -A FORWARD -s 192.168.1.0/24 -o eth0 -j ACCEPT
sudo iptables -A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -i eth0 -j ACCEPT

总结

iptables功能强大但语法复杂,学习的关键在于理解其“表与链”的结构和数据包的流动逻辑。在配置时,务必遵循“默认拒绝,按需允许”的安全原则,并始终在修改规则前做好备份,在设置默认DROP策略时预留好管理通道。多实践、多测试是掌握iptables的最佳途径。