iptables 简介
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等),决定下一步执行的情况,后续执行一般有三种情况.
- 一种是继续执行当前规则队列内的下一条规则。比如执行过Filter队列内的LOG后,还会执行Filter队列内的下一条规则。
- 一种是中止当前规则队列的执行,转到下一条规则队列。比如从执行过accept后就中断Filter队列内其它规则,跳到nat队列规则去执行
- 一种是中止所有规则队列的执行。
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-resetDROP
丢弃封包不予处理,进行完此处理动作后,将不再比对其它规则,直接中断过滤程序。
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-31000LOG
将封包相关讯息纪录在 /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-100MIRROR
镜射封包,也就是将来源 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。
参考
默认情况下,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
有什么方法可以影响这个端口的选择或衡量其选择的范围?
是的,可以通过在规则中使用masquerade或snat语句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 重传)