理解Linux内的iptables

iptables的原理与发展历史

iptables作为linux内核防火墙的命令行配置工具包,已经被广泛集成在各大Linux发行版本内。诸如Arch这类鼓励用户自定义linux kernel的发行版也自己默认集成了iptables,最小化安装完Arch之后也可以使用iptables修改与配置firewall。

理解iptables的用途无需去看某些博客,直接去Arch WikiWikipedia英文关联页面,就可以理解其设计思路与主要用途。在知道其主要用途之后,剩余问题就在于怎么使用命令行去配置它。

下面是Arch Wiki上关于iptables的介绍与描述:

iptables 用于检查、修改、转发、重定向以及/或丢弃 IP 数据包。用于过滤 IP 数据包的代码已经内置在内核中,并被组织为多个用途不同的“表”(tables)。每个表由一组预定义的链(chains)构成,而每条链又包含按顺序遍历的规则。每条规则由两部分组成:一组用于匹配数据包的条件,以及当条件为真时执行的动作(该动作被称为 目标 target)。如果 IP 数据包到达了某个内置链的末尾(包括空链),那么该链的默认策略(policy target)将决定数据包的最终命运。iptables 是用户态的工具,允许你操作这些链和规则。对于初学者来说,Linux 的 IP 路由和过滤机制可能相当复杂,但在实践中,最常见的用例(例如 NAT 和/或基础的互联网防火墙)其实并没有那么难。

理解 iptables 的关键是下面这张流程图:图中上方的小写单词表示表(table),下方的大写单词表示链(chain)。所有从任意网络接口进入的 IP 数据包都会从图的顶部进入,并按流程从上到下依次经过各链。一个常见误解是:来自内部接口的数据包与来自互联网接口的数据包会被不同方式处理。实际上,所有接口的数据包都会经过相同的路径,只是你可以通过规则来区别对待它们。当然,有些数据包是发给本机进程的,因此它们从流程图顶部进入,经过链后在Local Process(本地进程)处停止;而另一些数据包是本地进程自己生成的,因此它们从Local Process开始,再向下通过流程图继续处理。

iptables完整流程图

在大多数情况下,我们不需要使用raw, mangle, security表,因此,理解这张下面这张简化后的图表就已经足够我们使用iptables了。

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
26
27
28
29
30
31
32
33
34
                              XXXXXXXXXXXXXXXXXX
XXX Network XXX
XXXXXXXXXXXXXXXXXX
+
|
v
+-------------+ +------------------+
|table: filter| <---+ | table: nat |
|chain: INPUT | | | chain: PREROUTING|
+-----+-------+ | +--------+---------+
| | |
v | v
[local process] | **************** +--------------+
| +---------+ Routing decision +------> |table: filter |
v **************** |chain: FORWARD|
**************** +------+-------+
Routing decision |
**************** |
| |
v **************** |
+-------------+ +------> Routing decision <---------------+
|table: nat | | ****************
|chain: OUTPUT| | +
+-----+-------+ | |
| | v
v | +-------------------+
+--------------+ | | table: nat |
|table: filter | +----+ | chain: POSTROUTING|
|chain: OUTPUT | +--------+----------+
+--------------+ |
v
XXXXXXXXXXXXXXXXXX
XXX Network XXX
XXXXXXXXXXXXXXXXXX

综上所述,我们需要知道,iptables操纵的对象是IP报文。简化后的情况下,一则经某个特定Interface入栈的IP报文,首先经过nat表的PREROUTING链规则,随后在第一个Routing decision在此决定路由去向。一条去向是路由(Routing)(简单来说就是经过Interface再次转发出去),在这条路上,该报文还需要经过filter表的FORWARD链。而另外一条去向是传递给本地进程(进入传输层,通过端口号决定目标进程)(或者本地进程会发出IP报文,在图中该报文的出发点便为local process),同样的,在该路径还会经过多个表与链,包括filter表的INPUT链、NAT表的OUTPUT链、filter表的OUTPUT链。最后,这两条路径的报文都会来到第二个Routing decision节点,在此来决定此报文经由哪个Interface发出(不同子网的报文会经由不同的网卡发出),决定路径后在真正被网卡接口转发前,还需要经过nat表的POSTROUTING链。

理解iptables的命令

在使用iptables之前,有一点需要铭记,即iptables默认操作的表为最常用的filter表,如果需要操作其他表则需要使用-t指令指明表。同时,每个链内规则是按照顺序先后进行匹配的,也就是说如果第一条规则已经允许报文通过,则后续的规则都不会对该报文生效。因此每条规则在链中的位置也是很重要的,在编辑iptables的规则之前需要想好规则在链中的位置。

展示当前规则

使用--list-rules-S列出(指定的表)所包含的所有规则,例如下面的指令列出nat表内所有的规则:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ iptables -t nat -S

# Warning: iptables-legacy tables present, use iptables-legacy to see them
-P PREROUTING ACCEPT
-P INPUT ACCEPT
-P OUTPUT ACCEPT
-P POSTROUTING ACCEPT
-N DOCKER
-A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER
-A OUTPUT ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER
-A POSTROUTING -o eth0 -j MASQUERADE
-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE
-A DOCKER -i docker0 -j RETURN

其中,-P代表链的默认策略即policy的运作方式,可以看出,nat表内的四个链的默认策略全都是ACCEPT即接受该报文并向后传递。-N代表用户创建的新链,由于我自己机器上装了docker,安装docker时会增加一个新链DOCKER。后续的-A代表链内的规则(-A代表append,也就是直接在链的最后附上一条规则)。

还可以使用--list-L指令并接受更多修饰符来列出iptables内某个链的更详细的信息,例如,使用下述指令可以在verbose(-v)模式下并以数字ip地址的形式打印ip地址和端口号(-n)(默认是以Host名)列出nat表内POSTROUTING链的详细规则:

1
2
3
4
5
6
7
8
$ iptables -t nat -nvL POSTROUTING

# Warning: iptables-legacy tables present, use iptables-legacy to see them
Chain POSTROUTING (policy ACCEPT 344K packets, 29M bytes)
pkts bytes target prot opt in out source destination
684K 51M MASQUERADE 0 -- * eth0 0.0.0.0/0 0.0.0.0/0
0 0 MASQUERADE 0 -- * !docker0 172.17.0.0/16 0.0.0.0/0

重置规则

使用-F-X来刷新重置当前表内所有的自带链和删除所有非默认(用户自创)链,因此如果需要完全重置iptables所有的表与链,可以使用下列指令:

1
2
3
4
5
6
7
8
9
10
11
12
13
iptables -F
iptables -X
iptables -t nat -F
iptables -t nat -X
iptables -t mangle -F
iptables -t mangle -X
iptables -t raw -F
iptables -t raw -X
iptables -t security -F
iptables -t security -X
iptables -P INPUT ACCEPT
iptables -P FORWARD ACCEPT
iptables -P OUTPUT ACCEPT

编辑规则

学习如何编辑规则是了解iptables的重点,我们需要对一条规则,我们有四种操作方式分别为: -A在链后附上一条规则,-I在指定位置插入一条规则,-R替换某个位置的规则,-D删除某个位置的规则。同时-P可以修改默认策略(policy)。这时候我们可以拿之前创建pptp服务端时使用的那几条iptables指令举例来解释其到底做了什么(详情可以看我的另外一篇pptp的博客)。

下述指令在默认的表filter内插入了一条规则(不指名位置则在最开头插入),规则内容是INPUT链内对状态为NEW且目标端口为1723的tcp报文所执行的动作(target)变为ACCEPT。也就是说允许防火墙接受发向tcp端口1723的建立pptp连接的报文。实际上Arch linux默认的防火墙并没有对tcp报文有任何限制,在新机器上这条指令无效。

1
iptables -I INPUT -p tcp --dport 1723 -m state --state NEW -j ACCEPT

下述指令在nat表内的POSTROUTING链头(未指明位置)插入了一条规则,规则内容是对于输出目标为etho网卡的报文,采取动作(target) MASQUERADE(伪装,简单理解即将ip报文内的源ip改为当前主机eth0的出口ip地址),这样便坐到了NAT的效果,允许我们经过隧道发往server的报文可以正常NAT并传入互联网。

1
iptables -t nat -I POSTROUTING -o eth0 -j MASQUERADE

在知道如何编辑规则后我们应该就可以轻松读懂网上的那些iptables指令了。


理解Linux内的iptables
https://blog.bakeneko-kuro.com/2025/12/01/linux/iptable/
作者
迷途黑猫
发布于
2025年12月1日
许可协议