Iptables用于在 Linux 内核中设置、维护和检查 IP 数据包过滤规则表。可以定义多个不同的表。每个表包含多个内置链,也可能包含用户定义的链。

每个链都是一个规则列表,用于匹配一组数据包。每条规则指定了如何处理匹配的数据包。这被称为“target(目标)”,它可以跳转到同一个表中用户定义的链。

通常所说的四表五链为

四表:filter、nat、mangle、raw

五链:PREROUTING、INPUT、FORWARD、OUTPUT、POSTROUTING

四表五链

规则表:

1)filter表(默认 如果没有指定 -t 选项)——三个链:INPUT、FORWARD、OUTPUT
作用:过滤数据包 内核模块:iptables_filter.
2)Nat表——三个链:PREROUTING、POSTROUTING、OUTPUT
作用:用于网络地址转换(IP、端口) 内核模块:iptable_nat
3)Mangle表——五个链:PREROUTING、POSTROUTING、INPUT、OUTPUT、FORWARD
作用:修改数据包的服务类型、TTL、并且可以配置路由实现QOS内核模块:iptable_mangle(别看这个表这么麻烦,咱们设置策略时几乎都不会用到它)
4)Raw表——两个链:OUTPUT、PREROUTING
作用:决定数据包是否被状态跟踪机制处理 内核模块:iptable_raw

规则表之间的优先顺序:

Raw -> mangle -> nat -> filter

规则链:

PREROUTING: 数据包进入路由表之前,对数据包做路由选择前应用此链路中的规则,所有的数据包进来的时候都先由这个链处理。
INPUT:      通过路由表后目的为本机,进来的数据报应用此规则链上的策略。
FORWARD:    通过路由表后,目标地址不为本机,做转发数据报时应用此规则链上的策略。
OUTPUT:     由本机产生的外出的数据包向外转发时,应用此规则链中的策略。
POSTROUTING:数据报做路由选择后发送后到网卡接口之前应用此链中的规则,所有的数据包出来的时候都先由这个链处理。

数据包处理流程

                   封包进入
                      ↓
                   PREROUTING 链(匹配顺序: raw -> mangle -> nat)
                      ↓
                   路由决策(routing decision) 判断目标地址
                      ↓
    是发往本机          ↓                        不是发往本机
   ←←←←←←←←←←←←←←←←←←←-→→→→→→→→→→→→→→→→→→→→→→→→→→→→
   ↓                                              ↓
INPUT 链(mangle -> filter)                    FORWARD 链(mangle -> filter)
   ↓                                              ↓
本地进程(local process)
   ↓                                              ↓
路由决策(routing decision)
   ↓                                              ↓
OUTPUT 链(raw -> mangle -> nat -> filter)
   ↓                                              ↓
   →→→→→→→→→→→→→→→→→→→-←←←←←←←←←←←←←←←←←←←←←←←←←←←←
                      ↓
                      ↓
                   POSTROUTING 链(raw -> mangle -> nat -> filter) 
                      ↓
                   封包传出

iptables和route的优先级

NAT有改变源ip的叫SNAT,也有改变目的ip的叫DNAT, SNAT在路由之后, 因为只有查过路由之后才能知道从那个接口出去, 才能查找到接口ip,才能知道原ip要换成哪个;DNAT在路由之前, 因为进入路由是根据目的ip来查的。

  • 对进入的包 先NAT 再路由
  • 对出去的包 先路由 再NAT

iptables和route的处理顺序:

用户空间的请求包为出方向的数据包是这样走的:用户空间---->output----->(经过路由)------>postrouting
服务器收到入方向发往本机的数据包是这样走的:prerouting----->(经过路由)----->input----->用户空间

匹配规则:

从规则表中从上往下顺序执行,如果没有遇到匹配的规则,就一条一条的往下执行,如果遇到匹配的规则后,那么就执行本规则,执行后根据本规则的动作(accept, reject, log等),决定下一步执行的情况,后续执行一般有三种情况.

  1. 一种是继续执行当前规则队列内的下一条规则。比如执行过Filter队列内的LOG后,还会执行Filter队列内的下一条规则。
  2. 一种是中止当前规则队列的执行,转到下一条规则队列。比如从执行过accept后就中断Filter队列内其它规则,跳到nat队列规则去执行
  3. 一种是中止所有规则队列的执行。

iptables 是采用规则堆栈的方式来进行过滤,当一个封包进入网卡,会先检查 Prerouting,然后检查目的 IP 判断是否需要转送出去,接着就会跳到 INPUT 或 Forward 进行过滤,如果封包需转送处理则检查 Postrouting,如果是来自本机封包,则检查 OUTPUT 以及 Postrouting。过程中如果符合某条规则将会进行处理,处理动作除了 ACCEPT、REJECT、DROP、REDIRECT 和 MASQUERADE 以外,还多出 LOG、ULOG、DNAT、SNAT、MIRROR、QUEUE、RETURN、TOS、TTL、MARK 等,其中某些处理动作不会中断过滤程序,某些处理动作则会中断同一规则链的过滤,并依照前述流程继续进行下一个规则链的过滤(注意:这一点与 ipchains 不同),一直到堆栈中的规则检查完毕为止。透过这种机制所带来的好处是,我们可以进行复杂、多重的封包过滤,简单的说,iptables 可以进行纵横交错式的过滤(tables)而非链状过滤(chains)。

处理动作

ACCEPT

​ 将封包放行,进行完此处理动作后,将不再比对其它规则,直接跳往下一个规则链(nat:postrouting)。

REJECT

​ 拦阻该封包,并传送封包通知对方,可以传送的封包有几个选择:ICMP port-unreachable、ICMP echo-reply 或是 tcp-reset(这个封包会要求对方关闭联机),进行完此处理动作后,将不再比对其它规则,直接 中断过滤程序。 范例如下:

iptables -A FORWARD -p TCP ——dport 22 -j REJECT ——reject-with tcp-reset

DROP

​ 丢弃封包不予处理,进行完此处理动作后,将不再比对其它规则,直接中断过滤程序。

REDIRECT

​ 将封包重新导向到另一个端口(PNAT),进行完此处理动作后,将 会继续比对其它规则。 这个功能可以用来实作通透式 porxy 或用来保护 web 服务器。例如:iptables -t nat -A PREROUTING -p tcp ——dport 80 -j REDIRECT ——to-ports 8080  
MASQUERADE

​ 改写封包来源 IP 为防火墙 NIC IP,可以指定 port 对应的范围,进行完此处理动作后,直接跳往下一个规则链(mangle:postrouting)。这个功能与 SNAT 略有不同,当进行 IP 伪装时,不需指定要伪装成哪个 IP,IP 会从网卡直接读取,当使用拨接连线时,IP 通常是由 ISP 公司的 DHCP 服务器指派的,这个时候 MASQUERADE 特别有用。范例如下:

iptables -t nat -A POSTROUTING -p TCP -j MASQUERADE ——to-ports 1024-31000

LOG

​ 将封包相关讯息纪录在 /var/log 中,详细位置请查阅 /etc/syslog.conf 组态档,进行完此处理动作后,将会继续比对其它规则。例如:

iptables -A INPUT -p tcp -j LOG --log-prefix "INPUT packets"

SNAT

​ 改写封包来源 IP 为某特定 IP 或 IP 范围,可以指定 port 对应的范围,进行完此处理动作后,将直接跳往下一个规则链(mangle:postrouting)。范例如下:

iptables -t nat -A POSTROUTING -p tcp-o eth0 -j SNAT ——to-source 194.236.50.155-194.236.50.160:1024-32000

  注意:
  要查看 iptables 中的 SNAT 规则(源地址转换),可以使用以下命令:

sudo iptables -t nat -L -n

  这将列出 nat 表中的所有规则,并显示相应的源地址转换信息。
  如果您只希望查看 SNAT 相关的规则,可以使用 --line-numbers 参数来显示规则的行号,并使用 --match 参数指定匹配条件为 SNAT。例如:

iptables -t nat -L -n --line-numbers --match SNAT

  这将只显示与 SNAT 相关的规则,并包含它们的行号。
  请注意,执行以上命令需要具有适当的权限(通常需要以管理员身份运行)。

DNAT

​ 改写封包目的地 IP 为某特定 IP 或 IP 范围,可以指定 port 对应的范围,进行完此处理动作后,将会直接跳往下一个规则链(filter:input 或 filter:forward)。
  注意:DNAT target只能用在nat表的PREOUTING 和 OUTPUT 链中,或者是被这两条链调用的链里。但还要注意的是,包含DNAT target的链不能被除此之外的其他链调用,如POSTROUTING。
  范例如下:

iptables -t nat -A PREROUTING -p tcp -d 15.45.23.67 ——dport 80 -j DNAT ——to-destination 192.168.1.1-192.168.1.10:80-100

MIRROR

​ 镜射封包,也就是将来源 IP 与目的地 IP 对调后,将封包送回,进行完此处理动作后,将会中断过滤程序。

QUEUE

​ 中断过滤程序,将封包放入队列,交给其它程序处理。透过自行开发的处理程序,可以进行其它应用,例如:计算联机费用……等。

RETURN

​ 结束在目前规则链中的过滤程序,返回主规则链继续过滤,如果把自订规则链看成是一个子程序,那么这个动作,就相当于提早结束子程序并返回到主程序中。

MARK

​ 将封包标上某个代号,以便提供作为后续过滤的条件判断依据,进行完此处理动作后,将会继续比对其它规则。范例如下:

iptables -t mangle -A PREROUTING -p tcp ——dport 22 -j MARK ——set-mark 2

链的默认动作和规则匹配顺序

如果INPUT链为以下配置

root@K3S-PROD-001:/etc/ufw# sudo iptables -t filter -nvL INPUT
Chain INPUT (policy DROP 3 packets, 180 bytes)
 pkts bytes target     prot opt in     out     source               destination
 112M   40G ufw-before-logging-input  all  --  *      *       0.0.0.0/0            0.0.0.0/0

 112M   40G ufw-before-input  all  --  *      *       0.0.0.0/0            0.0.0.0/0

  91M   32G ufw-after-input  all  --  *      *       0.0.0.0/0            0.0.0.0/0

  91M   32G ufw-after-logging-input  all  --  *      *       0.0.0.0/0            0.0.0.0/0

  91M   32G ufw-reject-input  all  --  *      *       0.0.0.0/0            0.0.0.0/0

  91M   32G ufw-track-input  all  --  *      *       0.0.0.0/0            0.0.0.0/0


root@K3S-PROD-001:/etc/ufw# sudo iptables -t filter -S INPUT
-P INPUT DROP
-A INPUT -j ufw-before-logging-input
-A INPUT -j ufw-before-input
-A INPUT -j ufw-after-input
-A INPUT -j ufw-after-logging-input
-A INPUT -j ufw-reject-input
-A INPUT -j ufw-track-input

在这里,-P INPUT DROP 设置了 INPUT 链的默认动作为 DROP,表示除非有匹配的规则,否则所有的输入数据包都会被拒绝。

接下来的 -A INPUT -j ufw-before-logging-input-A INPUT -j ufw-before-input-A INPUT -j ufw-after-input 等是附加规则,它们会在默认规则之前按照顺序进行匹配。如果有任何一条规则匹配成功(根据规则的匹配条件),那么默认规则就不再执行。

简单来说,这几条规则可以被看作是在默认规则之前的检查点。如果有一条规则匹配,那么它的动作将被执行,而默认规则则不会生效。

DNAT后是进入 INPUT 还是 FORWARD

iptables 在nat表中 通过DNAT 后 是如何选择进入INPUT还是FORWARD

在 iptables 的 NAT 表中,通过 DNAT 进行目标地址转换后,数据包会被重新路由到转换后的目标地址。之后,数据包将按照网络层的规则进入适当的链,决定是进入 INPUT 链还是 FORWARD 链。

具体决定数据包进入 INPUT 链还是 FORWARD 链的规则如下:

  • 如果目标地址是本机(即 DNAT 后的目标地址是本机),数据包将进入 INPUT 链。
  • 如果目标地址是其他主机(即 DNAT 后的目标地址不是本机),数据包将进入 FORWARD 链。

所以,如果您在 iptables 的 NAT 表中使用 DNAT 进行目标地址转换,并且转换后的目标地址是本机的 IP 地址,数据包将进入 INPUT 链,经过进一步处理,如应用过滤规则、处理本地服务等。如果转换后的目标地址是其他主机的 IP 地址,数据包将进入 FORWARD 链,进行转发处理。

请注意,具体的处理流程可能会受到其他规则和配置的影响,例如网络层的路由规则、过滤规则等。因此,在实际应用中,需要根据具体的网络拓扑和需求来配置 iptables 规则,以确保数据包按照预期的方式进行转发和处理。

操作

使用DROP丢弃数据包

在 iptables 的 NAT 表中的 PREROUTING 链中,可以添加 DROP 规则来丢弃数据包。PREROUTING 链是数据包进入路由前的第一个链,用于进行目标地址转换(DNAT)等操作。

以下是在 PREROUTING 链中添加 DROP 规则的示例命令:

iptables -t nat -A PREROUTING -p tcp --dport 80 -j DROP

上述命令将在 PREROUTING 链中添加一个 DROP 规则,该规则将匹配目标端口为 80 的 TCP 数据包,并丢弃它们。

请注意,添加 DROP 规则时,要确保规则的位置和顺序是正确的。如果在 PREROUTING 链中的早期位置添加 DROP 规则,它将立即丢弃匹配的数据包,并且后续的规则将不再应用于这些数据包。因此,根据您的具体需求,需要仔细考虑规则的顺序和位置。

另外,添加规则到 iptables 需要 root 权限。请确保以 root 用户或使用 sudo 权限执行上述命令。

报错

root@JENKINS-003:~# iptables -t nat -A PREROUTING -p tcp --dport 80 -j DROP
iptables v1.6.1:
The "nat" table is not intended for filtering, the use of DROP is therefore inhibited.


Try `iptables -h' or 'iptables --help' for more information.

在 iptables 的 NAT 表中的 PREROUTING 链中,不能添加 DROP 规则来丢弃数据包。NAT 表主要用于地址转换和端口转发等操作,不适用于数据包过滤。

如果您想要丢弃数据包,应该在过滤表(Filter Table)中的 INPUT 链、FORWARD 链或 OUTPUT 链中添加 DROP 规则。这些链用于数据包的过滤和决策。

以下是在 Filter 表中的 INPUT 链中添加 DROP 规则的示例命令:

iptables -A INPUT -p tcp --dport 80 -j DROP

上述命令将在 INPUT 链中添加一个 DROP 规则,该规则将匹配目标端口为 80 的 TCP 数据包,并丢弃它们。

请注意,添加规则到 iptables 需要 root 权限。请确保以 root 用户或使用 sudo 权限执行上述命令。

查看SNAT

要查看 iptables 中的 SNAT 规则(源地址转换),可以使用以下命令:

iptables -t nat -L -n

这将列出 nat 表中的所有规则,并显示相应的源地址转换信息。

如果您只希望查看 SNAT 相关的规则,可以使用 --line-numbers 参数来显示规则的行号,并使用 --match 参数指定匹配条件为 SNAT。例如:

iptables -t nat -L -n --line-numbers --match SNAT

这将只显示与 SNAT 相关的规则,并包含它们的行号。

请注意,执行以上命令需要具有适当的权限(通常需要以管理员身份运行)。

执行报错,ubuntu 18.04

swift@SWIFT-WAF-001:~$ sudo iptables -t nat -L -n --line-numbers --match SNAT
iptables v1.6.0: Couldn't load match `SNAT':No such file or directory

Try `iptables -h' or 'iptables --help' for more information.

记录数据包日志 LOG

Example

要捕获 iptables NAT 表中 PREROUTING 链中的 DNAT 包,可以使用如下的方法:

使用 iptables 命令将 PREROUTING 链中的 DNAT 包重定向到一个用户定义的链。
sudo iptables -t nat -N MY_CHAIN
sudo iptables -t nat -A PREROUTING -j MY_CHAIN

在用户定义的链上设置 LOG 规则来记录 DNAT 包。
sudo iptables -t nat -A MY_CHAIN -j LOG --log-prefix "DNAT Packet: "

这样,当有 DNAT 包经过 PREROUTING 链时,会被重定向到 MY_CHAIN 链上,并且被记录下来。您可以在系统的日志文件中查看记录的 DNAT 包。

请注意,此方法可能会在系统日志中生成大量的日志记录,因此在生产环境中使用时请谨慎。您可以根据具体情况调整日志记录的级别和频率。

实例

# 一条规则
sudo iptables -t nat -I PREROUTING -p tcp --dport 6379 -j DNAT --to-destination 10.73.1.188:6379

# 若需要记录该规则,则需要添加
sudo iptables -t nat -I PREROUTING 1 -p tcp --dport 6379 -j LOG --log-prefix "DNAT Packet: "

# 删除
sudo iptables -t nat -D PREROUTING -p tcp --dport 6379 -j LOG --log-prefix "DNAT Packet: "
# 或者
sudo iptables -t nat -D PREROUTING 1

如何查看

iptables 日志记录的位置取决于您的系统和日志配置。通常情况下,iptables 日志将会记录在系统的系统日志文件中,例如 /var/log/messages 或 /var/log/syslog。您可以使用 grep 命令来过滤日志文件中与规则前缀相匹配的日志条目,例如:

grep "DNAT Packet" /var/log/messages

或者

grep "DNAT Packet" /var/log/syslog

请注意,确保在查看日志之前已经启用了 iptables 日志记录功能,并且检查您的日志配置以确定确切的日志文件路径和格式。

swift@SWIFT-WAF-001:/var/log$ sudo grep "DNAT Packet" /var/log/syslog
Mar 26 20:41:56 LOCALTEST-DEV-001 kernel: [5283981.062211] DNAT Packet: IN=eno1 OUT= MAC=98:90:96:bb:73:1c:08:68:8d:2e:9b:4e:08:00 SRC=192.168.20.11 DST=192.168.1.15 LEN=60 TOS=0x10 PREC=0x00 TTL=62 ID=21084 DF PROTO=TCP SPT=53792 DPT=6379 WINDOW=64240 RES=0x00 SYN URGP=0

目标扩展 TARGET EXTENSIONS

MASQUERADE

该目标只在 nat 表的 POSTROUTING 链中有效。它只能用于动态分配的 IP(拨号)连接:如果使用的是静态 IP 地址,则应使用 SNAT 目标。伪装等同于指定数据包输出接口的 IP 地址映射,但也会在接口宕机时遗忘连接。当下一次拨号不太可能使用相同的接口地址时,这是正确的行为(因此任何已建立的连接都会丢失)。

--to-ports port[-port]

指定要使用的源端口范围,覆盖 SNAT 默认的源端口选择启发式方法(见上文)。只有当规则还指定了以下协议之一时才有效:TCP、UDP、DCCP 或 SCTP。

--random

随机化源端口映射 如果使用选项--random,端口映射将被随机化(内核 >= 2.6.21)。自内核 5.0 起,--random 与 --random-fully 相同。

--random-fully

完全随机化源端口映射 如果使用 --random-fully 选项,端口映射将完全随机化(内核 >= 3.13)。

自 Linux 内核 >= 3.7 起支持 IPv6。

也可以参考 iptables

--to-ports port[-port]

指定要使用的源端口范围,覆盖 SNAT 默认的源端口选择启发式方法(见上文)。只有当规则还指定了 -p tcp 或 -p udp 时才有效。

SNAT

该目标仅在 nat 表、POSTROUTING 链和 INPUT 链以及仅从这些链调用的用户自定义链中有效。它指定修改数据包的源地址(此连接中所有未来的数据包也将被篡改),并停止检查规则。它包含以下选项:

--to-source [ipaddr[-ipaddr]][:port[-port]]
可以指定一个新的源 IP 地址或一个包含的 IP 地址范围。如果规则还指定了以下协议之一:TCP、UDP、DCCP 或 SCTP,则可选择端口范围。如果没有指定端口范围,那么 512 以下的源端口将被映射到 512 以下的其他端口:512 至 1023(含 1023)之间的源端口将被映射到 1024 以下的端口,其他端口将被映射到 1024 或以上的端口。在可能的情况下,不会对端口进行更改。在 2.6.10 及以下的内核中,可以添加多个 --to-source 选项。在这些内核中,如果通过地址范围或多个 --to-source 选项指定了多个源地址,这些地址之间将进行简单的循环(一个接一个循环)。后来的内核(>= 2.6.11-rc1)不再支持 NAT 到多个范围。

--random
如果使用 --random 选项,端口映射将通过基于哈希的算法随机化(内核 >= 2.6.21)。

--random-fully
如果使用选项 --random-fully ,端口映射将通过 PRNG 进行完全随机化(内核 >= 3.14)。

--persistent
为客户端的每个连接提供相同的源地址/目标地址。这将取代 SAME 目标。从 2.6.29-rc2 开始支持持久映射。

2.6.36-rc1 之前的内核不支持 INPUT 链中的 SNAT。

从 Linux 内核 >= 3.7 开始支持 IPv6。

参考

如何选择iptables SNAT目标的源端口

默认情况下,SNAT 目标会保留原始数据包的源端口。如果该端口已被使用,它会随机选择一个。有什么方法可以影响此端口的选择,或者控制其选择的范围吗?在我的测试中,net.ipv4.ip_local_port_range似乎没有影响。我想知道是否有其他设置可以解决这个问题。

答:

默认情况下,SNAT 目标会保留原始数据包的源端口。如果该端口已被使用,则会随机选择一个。

它不是默认随机选择的,而是以下默认算法
(粗体部分证实了您关于保留原始端口的声明)

如果未指定端口范围,则低于 512 的源端口将被映射到其他低于 512 的端口:512 到 1023 之间的端口将被映射到低于 1024 的端口,其他端口将被映射到 1024 或以上的端口。在可能的情况下,不会发生端口变更。

https://man7.org/linux/man-pages/man8/iptables-extensions.8.html

有什么方法可以影响这个端口的选择或衡量其选择的范围?

是的,可以通过在规则中使用masqueradesnat语句NAT指定端口范围来实现,如下所示--to-ports port[-port]

--to-ports 端口[-port]
          This specifies a range of source ports to use, overriding
          the default SNAT source port selection heuristics (see
          above). This is only valid if the rule also specifies one
          of the following protocols: tcp, udp, dccp or sctp.

https://man7.org/linux/man-pages/man8/iptables-extensions.8.html

在我的测试中,net.ipv4.ip_local_port_range 似乎对此没有影响。

适用net.ipv4.ip_local_port_range于必须可用才能被监听的监听器端口,它与 无关SNAT,也就是说,这些端口NAT实际上永远不会被 使用。

https://www.ibm.com/docs/en/filenet-p8-platform/5.5.x?topic=listener-linux

NAT local port collision and SYN retransmit (NAT 分配端口冲突与 SYN 重传)

标签: iptables

添加新评论