BetaThis is a live doc! Anyone with edit access can make updates in real time without having to publish.
iptables

基础

全文纲领:iptables 的规则就是在特定的阶段如果满足特定的条件则做什么动作

我觉得网上各种表述太乱了,所以这个定义是我自己为了方便理解定义的,使用的并非标准术语


虽然这篇文章后面也多多少少会涉及到一些标准定义中的术语,但是仍建议你读完我写的这个以后去看看官方文档或者其他人写的文章,对照理解

iptables 不过是一个规则匹配引擎

一条 iptables 规则不过是

1if (条件 matched) { 2 // 做什么动作 3 // + 结束 4}
  • 条件:满足什么条件才执行这个规则,包括无条件(始终执行)、满足某些条件(例如是 TCP 流量)

  • 动作:在满足上述条件时会做什么,可能是允许或拒绝流量包、可能是修改包的目的 IP、也可能只是简单记录下日志

    • 结束:某些动作(例如允许/拒绝流量包)执行完可能就结束了(即不会再执行下面的规则),而某些则会继续执行下一条规则(例如修改包、或是记录日志等)

而 iptables 整体不过是

1if (阶段 matched) { 2 rules = get_all_rules_for(阶段) 3 4 for rule in rules { 5 执行上面那个代码块 6 } 7}
  • 阶段:一个网络包从进入系统到完成它的使命有若干阶段,iptables 就是定义了在某一阶段时有哪些规则然后对应应用这些规则(即上面讲的「一条 iptables 规则不过是」)

阶段

iptables 利用「表」和「链」来定义规则,这个表与链的关系怎么说呢,非要我说就是「混乱」

iptables 有五个链 PREROUTING / INPUT / OUTPUT / POSTROUTING / FORWARD 和四个表 raw / mangle / nat / filter,来看看流量从进入机器到离开机器是怎么经过这些链和表的

image-20241021-093628.png

Linux 将流量区分为本地流量(流量来源或目的地有一个是本机)和转发流量(流量来源和目的地均不是本机),简单点理解就是,平常我们服务接收和发送的都是本地流量,而路由器将机器 A 的流量转发给机器 B 则是转发流量。

而流量进入系统以后,iptables 怎么匹配流量请见👇(实际就是上面的图用文字描述了下)

对于本地流量进入而言,匹配过程是这样子的

  • 流量进入

  • 匹配 raw 表中的 PREROUTING 链上的规则

  • 匹配 mangle 表中的 PREROUTING 链上的规则

  • 匹配 nat 表中的 PREROUTING 链上的规则

  • 匹配 mangle 表中的 INPUT 链上的规则

  • 匹配 filter 表中的 INPUT 链上的规则

  • 到达目标应用

对于本地流量离开而言,是这样子的

  • 流量流出

  • 匹配 raw 表中的 OUTPUT 链上的规则

  • 匹配 mangle 表中的 OUTPUT 链上的规则

  • 匹配 nat 表中的 OUTPUT 链上的规则

  • 匹配 filter 表中的 POSTROUTING 链上的规则

  • 匹配 raw 表中的 POSTROUTING 链上的规则

  • 匹配 mangle 表中的 POSTROUTING 链上的规则

  • 匹配 nat 表中的 POSTROUTING 链上的规则

  • 流量成功流出

对于转发流量,则是这样子的

  • 流量进入

  • 匹配 raw 表中的 PREROUTING 链上的规则

  • 匹配 mangle 表中的 PREROUTING 链上的规则

  • 匹配 nat 表中的 PREROUTING 链上的规则

  • 匹配 mangle 表中的 FORWARD 链上的规则

  • 匹配 filter 表中的 FORWARD 链上的规则

  • 匹配 filter 表中的 POSTROUTING 链上的规则

  • 匹配 raw 表中的 POSTROUTING 链上的规则

  • 匹配 mangle 表中的 POSTROUTING 链上的规则

  • 匹配 nat 表中的 POSTROUTING 链上的规则

  • 流量转发成功

emmm,上面就是很完整的 iptables 流量的匹配过程,不知道你晕不晕,我是很久都没弄明白链和表到底有啥关系,总感觉像是「互相影响」的「缠绕」关系。。。

所以我觉得,尽量还是将二者作为一个组合去理解,特别是初期,不要苛求「为什么 xx 是这样子的」

我写了一个我的理解方式(因为本身这个定义就很混乱,所以我写的这个实际上也并不完全准确,仅供参考):

这个理解方式一定不能单独看,单独看的表述会容易产生误解甚至是错误的,请结合下图看

外层的 PREROUTING / INPUT / OUTPUT / POSTROUTING / FORWARD 是链
链里面的 raw / mangle / nat / filter 是表

  • 网络包从进入机器到流出机器,会经过若干个环节,这些每一个环节称为「链 chain」

  • 在每个环节「链 chain」中,会进行若干操作,这些操作由各个「表 table」定义

  • 每个「表 table」中存在若干条规则,会顺序执行

链 chain

根据网络流量的来源与目的不同,存在两种不同可能的流量流过链的顺序

  • 本机流量:PREROUTING → INPUT → (app) → OUTPUT → POSTROUTING

  • 转发流量:PREROUTING → FORWARD → POSTROUTING

一共五种链,作用各不相同

  • PREROUTING 处理刚到达本机、在路由转发前的数据包

    • 在 raw, mangle, nat 表中存在

    • 可以修改数据包的目标地址、端口等

    • 用处

      • 端口映射

      • SNAT - 匿名访问 / 欺骗攻击

      • DNAT - NAT 转换 / 负载均衡

  • POSTROUTING 处理将要离开本机的数据包

    • 在 mangle, nat 表中存在

    • 对数据包的源 IP 地址进行 NAT 转换或者修改规则的匹配等操作

    • 用处

      • SNAT - NAT 转换,将内部 IP 地址转换为公网 IP 地址,从而实现外部网络对本地设备的访问

        • Masquerade:Masquerade 是一种特殊的 SNAT 操作,通过将数据包源地址都修改为本机的公网 IP 地址来实现 NAT 转换,通常用于连接互联网的本地网络设备,如路由器等

      • 连接跟踪 conntrack:记录数据包的状态信息,跟踪连接的建立、维护和释放

      • 防火墙:通过设置过滤规则来保护本机或网络设备的安全和隐私

  • INPUT 处理传入数据包

    • 在 mangle, filter 表中存在

    • 用处

      • 防火墙

      • 服务访问控制

      • ICMP 控制

      • 连接跟踪

  • OUTPUT 处理传出数据包

    • 在 raw, mangle, nat, filter 表中存在

    • 用处

      • 防火墙

      • 服务访问控制

      • NAT 转换

      • 连接跟踪

  • FORWARD 处理转发的包

    • 在 mangle, filter 表中存在

    • 用处

      • 网络隔离:仅允许特定包经过

      • NAT 转换

      • 负载均衡

      • 连接跟踪

表 table

根据用处不同,分成了不同的表(每个链包括不同的表)

  • raw:实现包的状态跟踪

    • 有 PREROUTING, OUTPUT 两个链

    • 优先级最高,在连接跟踪前处理

    • 一旦某个链启用了 raw 表,流量将跳过 nat 表和 ip_conntrack 处理

  • mangle:实现包修改

    • 有 INPUT, OUTPUT, PREROUTING, POSTROUTING, FORWARD 五个链

    • 除了修改,还可以用来标记数据包或重定向数据包

  • nat:实现网络地址转换(修改包的 ip 和端口)

    • 有 PREROUTING, POSTROUTING, OUTPUT 三个链

  • filter:实现包的过滤

    • 有 INPUT, OUTPUT, FORWARD 三个链

    • 在使用命令但不指定任何表时,默认为 filter 表

当流量到链中匹配时,按照如下顺序匹配表中的规则:raw → mangle → nat → filter

命令行

规则操作

iptables [-t 表] -命令 链 [条件] -j 动作

这是 iptables 的操作命令,由四个基础概念「表、链、条件、动作」和一个仅供 CLI 的「命令」组成。

最常用的 -A,将这条规则加在这个表的最后

1iptables [-t 表] -A 链 [条件] -j 动作

因为 iptables 是顺序的,所以也可能将链加到某一规则前面,例如想加到第 X 条规则前面(1-based)

1iptables [-t 表] -I 链 X [条件] -j 动作

X 也是可以省略的 —— 此时 X=1,相当于插入到最前面

1iptables [-t 表] -I 链 [条件] -j 动作

可以通过将添加时的 -A 改成 -D 来删除

1iptables [-t 表] -D 链 [条件] -j 动作

也可以通过指定规则的序号来删除(1-based)

1iptables [-t 表] -D 链 X

如果想要清空所有规则(flush)

1iptables [-t 表] -F [链]
  • 如果指定链,清空整条链;如果不指定链,清空表下所有链

改(替换)

iptables 的规则不存在真正意义的「修改」,实际上是「替换 Replace」,相当于删除原有位置的规则然后在相同的位置插入了一个新的

例如,想修改(替换)第 X 条规则(1-based)

1iptables [-t 表] -R 链 X [条件] -j 动作

判断指定的规则是否存在,只需将添加时的 -A 改成 -C(check)

1iptables [-t 表] -C 链 [条件] -j 动作

退出码:规则存在返回 0,否则返回非 0

Chain 操作 - 增删改

创建新的链

1iptables [-t 表] -N 链

删除某条链

1iptables [-t 表] -X 链
  • 删除前必须保证链为空(即先 flush)

重命名某条链,例如 A 改成 B

1iptables [-t 表] -E A B

列出所有规则

列出指定表指定链的所有规则

1iptables [-t 表] -L [链] -n
  • 未提供表:使用 filter 表

  • 未提供链:列出所有链

  • -n 是可选的,但是如果不指定返回会很慢(DNS 反查)

  • 额外 -x 参数可以让计数器显示为精确值(否则是人类友好值)

  • 额外 --line 参数可以显示规则的序号

如果想用类似 iptables-save 的方式来输出

1iptables [-t 表] -R [链]

iptables / ip6tables / nftables

iptables 仅针对 IPv4 生效、ip6tables 仅针对 IPv6 生效

因为 iptables 愈加复杂,Netfilter 组织(也是 iptables 的维护者)推出 nftables;nftables 与 iptables 类似,但语法更加简单(同时兼容 iptables 语法),并同时支持 IPv4 + IPv6

为了让一个文件同时兼容 iptables-restoreip6tables-restore,规则命令行中增加 -4-6 参数,在不正确的版本下会自动忽略规则而不会报错

常用规则

条件

匹配源地址 -s

1# 匹配多个 IP 2iptables -t filter -I INPUT -s 192.168.1.111,192.168.1.118 -j DROP 3 4# 匹配网段 5iptables -t filter -I INPUT -s 192.168.1.0/24 -j ACCEPT 6 7#匹配取反 8iptables -t filter -I INPUT ! -s 192.168.1.0/24 -j ACCEPT

匹配目标地址 -d

1# 匹配多个 IP 2iptables -t filter -I OUTPUT -d 192.168.1.111,192.168.1.118 -j DROP 3 4# 匹配网段 5iptables -t filter -I INPUT -d 192.168.1.0/24 -j ACCEPT 6 7#匹配取反 8iptables -t filter -I INPUT ! -d 192.168.1.0/24 -j ACCEPT

匹配协议 -p

可以匹配的协议类型 tcp、udp、udplite、icmp、esp、ah、sctp 等(centos7 中还支持 icmpv6、mh)

1iptables -t filter -I INPUT -p tcp -s 192.168.1.146 -j ACCEPT 2iptables -t filter -I INPUT ! -p udp -s 192.168.1.146 -j ACCEPT

匹配网卡 -i / -o

匹配流入网卡,在 OUTPUT 链与 POSTROUTING 链中不能使用此选项。

1iptables -t filter -I INPUT -p icmp -i eth4 -j DROP 2 3iptables -t filter -I INPUT -p icmp ! -i eth4 -j DROP

匹配流出网卡,在 INPUT 链与 PREROUTING 链中不能使用此选项。

1iptables -t filter -I OUTPUT -p icmp -o eth4 -j DROP 2 3iptables -t filter -I OUTPUT -p icmp ! -o eth4 -j DROP

扩展条件

扩展条件需要模块支持,常见的扩展模块有:tcp, udp

要使用扩展条件,必须先使用 -m 参数指定对应模块,但如果你指定了协议,则默认会使用与协议同名的模块

匹配连续 ip -m iprange --src-range

-s 能匹配 ip,能匹配 ip 段,能匹配离散 ip,但不能匹配随意的连续 ip。

若想匹配随意的连续 ip,可以使用 iprange 模块

1iptables -A INPUT -d 172.16.1.100 -p tcp --dport 80 -m iprange --src-range 172.16.1.5-172.16.1.10 -j DROP

匹配连续端口 -m tcp/udp --sport

1#示例如下 2iptables -t filter -I OUTPUT -d 192.168.1.146 -p tcp -m tcp --sport 22 -j REJECT 3 4# 连续端口 5iptables -t filter -I INPUT -s 192.168.1.146 -p tcp -m tcp --dport 22:25 -j REJECT 6 7# 匹配 0-22 和 80-65535 的端口 8iptables -t filter -I INPUT -s 192.168.1.146 -p tcp -m tcp --dport :22 -j REJECT 9iptables -t filter -I INPUT -s 192.168.1.146 -p tcp -m tcp --dport 80: -j REJECT 10 11# 端口匹配取反 12iptables -t filter -I OUTPUT -d 192.168.1.146 -p tcp -m tcp ! --sport 22 -j ACCEPT

匹配离散端口 -m multiport --dport

1iptables -t filter -I INPUT -s 192.168.1.146 -p tcp -m multiport --dport 22,80 -j REJECT

匹配 MAC 地址 -m mac --mac-source

mac 模块可以指明源 MAC 地址,,适用于:PREROUTING, FORWARD,INPUT chains

1iptables -A INPUT -s 172.16.0.100 -m mac  --mac-source  00:50:56:12:34:56 -j ACCEPT 2iptables -A INPUT -s 172.16.0.100  -j REJECT

匹配报文数据 -m string

使用 string 模块,可以对报文中的应用层数据做字符串模式匹配检测。

1iptables -A OUTPUT -p tcp --sport 80 -m string --algo bm --from 62 --string "google" -j REJECT

对应的参数解释

  • --algo:字符串匹配检测算法,可选值有:bm (Boyer-Moore)与 kmp (Knuth-Pratt-Morris)

  • --from:开始偏移

  • --to:结束偏移

  • [!] --string:匹配的字符串(是否取反)

  • [!]--hex-string:匹配字符串模式,16 进制格式(是否取反)

匹配收发速率 -m limit

1iptables -t filter -I INPUT -p icmp -m limit --limit-burst 3 --limit 10/minute -j ACCEPT 2iptables -t filter -A INPUT -p icmp -j REJECT
  • --limit-burst:类比” 令牌桶” 算法,此选项用于指定令牌桶中令牌的最大数量

  • --limit:类比” 令牌桶” 算法,此选项用于指定令牌桶中生成新令牌的频率,可用时间单位有 second、minute 、hour、day。

匹配并发数 -m connlimit

connlimit 模块是 iptables 中的一个扩展模块,用于控制连接数,限制每个源 IP 地址的并发连接数。

使用 connlimit 模块可以有效地保护服务器免受 DDoS(分布式拒绝服务)攻击,防止某个 IP 地址通过大量并发连接造成服务器负载过高,影响正常的网络服务。

connlimit 模块的工作原理是通过检查 iptables 所匹配到的连接数来实现连接限制。用户可以设置多种参数,如 --connlimit-above 用于限制允许的最大连接数,--connlimit-mask 用于指定判断连接数的掩码,--connlimit-upto 用于限制每个 IP 地址的允许最大连接数。

下面是一个示例规则,用于限制每个 IP 地址在 TCP 端口 80 上的最大连接数为 10:

1iptables -I INPUT -p tcp --dport 80 -m connlimit --connlimit-above 10 -j DROP

上述规则表示如果某个 IP 地址建立的连接数超过了 10,则将该 IP 地址的所有连接都丢弃。

除了限制连接数之外,还可以在特定情况下排除某些 IP 地址对于连接数控制的限制,例如允许某些代理服务器或特定的 IP 地址建立更多的连接。具体操作可以使用感叹号 "!" 对特定的 IP 地址进行标记以进行放开,例如:

1iptables -I INPUT -p tcp --dport 80 -m connlimit --connlimit-above 10 --connlimit-mask 32 ! -s 192.168.1.1 -j DROP

这条规则允许 IP 地址为 192.168.1.1 的主机建立更多的连接,而其他主机则被限制连接数不超过 10。

匹配状态 -m state

state 模块是 iptables 中的一个扩展模块,用于匹配 TCP 连接的状态。

TCP 连接有多种状态

  • ESTABLISHED 表示连接已经建立,可以进行正常的数据传输

  • NEW 表示新的连接请求,即 SYN 标志位被设置

  • RELATED 表示与已经建立的连接相关的连接,例如 FTP 传输和 DNS 查询使用的 UDP 连接

  • INVALID 表示无效的连接,可能由于网络原因等导致的连接错误。

state 模块可以帮助 iptables 根据连接状态进行过滤,从而有效地保护服务器免受攻击。

动作

用 -j (即 jump)来指定动作,动作可以是内置动作,也可以是自定义动作

  • 内置动作:如 ACCEPT,DROP,REJECT

  • 自定义动作:后面自定义链

ACCEPT

1iptables -I INPUT -s 192.168.1.146 -j ACCEPT

REJECT

1iptables -I INPUT -s 192.168.1.146 -j REJECT

还可以用 –reject-with 来设置提示信息,可选值有:

  • icmp-net-unreachable

  • icmp-host-unreachable

  • icmp-port-unreachable,

  • icmp-proto-unreachable

  • icmp-net-prohibited

  • icmp-host-prohibited

  • icmp-admin-prohibited

当不设置任何值时,默认值为 icmp-port-unreachable

DROP

1iptables -I INPUT -s 192.168.1.146 -j DROP

常用命令

屏蔽 ip 地址

1iptables -A INPUT -s 1.2.3.4 -j DROP 2iptables -A INPUT -s 192.168.0.0/24 -j DROP

屏蔽入站端口

1iptables -A INPUT -p tcp -s 1.2.3.4 --dport 80 -j DROP 2iptables -A INPUT -i eth1 -p tcp -s 192.168.1.0/24 --dport 80 -j DROP

屏蔽出站 IP

1iptables -A OUTPUT -d 192.168.1.0/24 -j DROP 2iptables -A OUTPUT -o eth1 -d 192.168.1.0/24 -j DROP

记录并删除包

1iptables -A INPUT -i eth1 -s 10.0.0.0/8 -j LOG --log-prefix "IP_SPOOF A: " 2iptables -A INPUT -i eth1 -s 10.0.0.0/8 -j DROP

通过 MAC 地址过滤数据

1iptables -A INPUT -m mac --mac-source 00:0F:EA:91:04:08 -j DROP

只接收 MAC 地址为 00:0F:EA:91:04:07 的 TCP 流量

1iptables -A INPUT -p tcp --destination-port 22 -m mac --mac-source 00:0F:EA:91:04:07 -j ACCEPT

过滤 ICMP ping 请求

1iptables -A INPUT -p icmp --icmp-type echo-request -j DROP 2iptables -A INPUT -i eth1 -p icmp --icmp-type echo-request -j DROP

开启范围端口

1iptables -A INPUT -m state --state NEW -m tcp -p tcp --dport 7000:7010 -j ACCEPT

开启范围 IP

1iptables -A INPUT -p tcp --destination-port 80 -m iprange --src-range 192.168.1.100-192.168.1

允许所有以太网帧(包括 ARP 请求)进入本机

1iptables -A INPUT -i eth0 -p all -m state --state RELATED,ESTABLISHED -j ACCEPT

允许 SSH 流量进入本机

1iptables -A INPUT -i eth0 -p tcp --dport 22 -m state --state NEW,ESTABLISHED -j ACCEPT 

允许 PING 流量通过本机

1iptables -A INPUT -i eth0 -p icmp --icmp-type echo-request -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT

允许 HTTP/HTTPS 流量进入本机

1iptables -A INPUT -i eth0 -p tcp --dport 80 -m state --state NEW,ESTABLISHED -j ACCEPT 2iptables -A INPUT -i eth0 -p tcp --dport 443 -m state --state NEW,ESTABLISHED -j ACCEPT

More

内核协议栈各 hook 点位置和 iptables 规则优先级经典配图

image-20241021-100419.png


参考

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

https://lixiangyun.gitbook.io/iptables_doc_zh_cn#gui-ze-biao-he-lian

https://juejin.cn/post/7214378356686831677

https://arthurchiao.art/blog/deep-dive-into-iptables-and-netfilter-arch-zh/

https://www.digitalocean.com/community/tutorials/a-deep-dive-into-iptables-and-netfilter-architecture

https://arthurchiao.art/blog/nat-zh/