Skip to content

Commit 53b14be

Browse files
committed
firewall: Match and jump
1 parent 5a12fae commit 53b14be

File tree

1 file changed

+75
-27
lines changed

1 file changed

+75
-27
lines changed

docs/ops/network/firewall.md

Lines changed: 75 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -113,46 +113,94 @@ iptables -P OUTPUT ACCEPT
113113

114114
注意到 `-L`, `-S`, `-F`, `-X`, `-Z` 这些命令都可以省略链名参数,表示对所有链进行操作。
115115

116+
完整的 iptables 规则语法和选项可以参考 [iptables(8)][iptables.8][iptables-extensions(8)][iptables-extensions.8] 手册页。
117+
116118
#### 规则匹配条件 {#iptables-match}
117119

118120
在「规则匹配条件」部分,可以使用多种匹配模块来指定数据包的特征,如源地址、目的地址、协议类型、端口号等。
119121
匹配的顺序是按命令行参数的顺序依次进行的,只有当数据包满足所有匹配条件时,才会应用该规则的目标。
120-
以科大镜像站上用于限制 80 / 443 端口并发连接数的规则为例:
121122

122-
```shell
123-
iptables -A LIMIT \
124-
-p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN \
125-
-m multiport --dports 80,443 \
126-
-m connlimit --connlimit-above 12 --connlimit-mask 29 --connlimit-saddr \
127-
-j REJECT --reject-with tcp-reset
128-
```
123+
常用的匹配规则包括:
124+
125+
`-s` / `--source` / `-d` / `--destination`
126+
127+
: 指定源地址或目的地址,可以是单个 IP 地址、CIDR 块或域名。一个 `-s``-d` 参数可以指定最多 15 个 IP 地址或 CIDR 块,多个地址之间用逗号分隔。
128+
129+
`-p` / `--protocol`
129130

130-
这条命令的理解方式如下:
131+
: 指定 IP 数据包内层的协议,如 `tcp``udp``icmp` 等。
131132

132-
- `iptables -A LIMIT`:将规则追加(`-A`)到名为 LIMIT 的链中,该规则只会对 IPv4 数据包生效。IPv6 防火墙规则需要使用 `ip6tables`
133-
- `-p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN`:匹配 TCP 协议的数据包,且匹配仅有 SYN 标志位被设置的数据包(即新连接请求)。
134-
- 等价的写法是 `-p tcp --syn`
135-
- 另一个(几乎)等价的写法是 `-m conntrack --ctstate NEW`,该写法事实上调用了连接跟踪模块,匹配将要建立新连接的数据包。
136-
- `-m multiport --dports 80,443`:调用 `multiport` 模块,匹配目的端口为 80 或 443 的数据包。
137-
- `-m tcp` 模块和 `-m udp` 模块也提供了 `--port` 参数,但只能用于单个端口的匹配,因此此处使用 `multiport` 模块来同时匹配多个端口。
138-
- `-m connlimit --connlimit-above 12 --connlimit-mask 29 --connlimit-saddr`:调用 `connlimit` 模块,匹配来自同一子网(掩码长度 29,即每 8 个 IP 地址为一个子网)且当前已建立连接数超过 12 的数据包。
139-
- `-j REJECT --reject-with tcp-reset`:目标为 REJECT,即主动拒绝匹配的数据包,并发送 TCP RST 响应给对端。
133+
`--sport` / `--dport`
140134

141-
iptables 规则的目标(`-j` 参数)可以是内置目标(如 ACCEPT、DROP、REJECT 等),也可以是用户自定义链的名称(跳转至自定义链继续处理),从而实现复杂的防火墙逻辑
135+
: 指定源端口号或目的端口号,可以是单个端口号或端口范围(格式为 `起始端口-结束端口`)。该选项只能与 `-p tcp``-p udp` 一起使用
142136

143-
由于 Netfilter 的结构和设计考虑,`-i`(输入接口)和 `-o`(输出接口)这两个匹配选项在不同阶段的可用性有所不同:
137+
该参数事实上由 `-m tcp` 或 `-m udp` 模块提供,而 iptables 会根据 `-p` 参数自动加载相应的模块,因此不需要显式指定 `-m tcp` 或 `-m udp`。
138+
出于同样的原因,你也无法在一条规则内同时匹配 TCP 和 UDP 协议的端口号,需要分别使用两条规则来实现。
144139

145-
| 阶段 | 可以使用 `-i` | 可以使用 `-o` |
146-
| :---------: | :--------------------------------------: | :---------------------------------------------------: |
147-
| PREROUTING | :fontawesome-solid-check:{: .limegreen } | :fontawesome-solid-xmark:{: .orangered } |
148-
| INPUT | :fontawesome-solid-check:{: .limegreen } | :fontawesome-solid-xmark:{: .orangered } |
149-
| FORWARD | :fontawesome-solid-check:{: .limegreen } | :fontawesome-solid-check:{: .limegreen } |
150-
| OUTPUT | :fontawesome-solid-xmark:{: .orangered } | :fontawesome-solid-check:{: .limegreen }[^output-oif] |
151-
| POSTROUTING | :fontawesome-solid-xmark:{: .orangered } | :fontawesome-solid-check:{: .limegreen } |
140+
此参数只能匹配一个端口号或一个端口范围(包含起止端口号),如果需要匹配多个不连续的端口号,可以使用 `-m multiport --sports` / `--dports` 模块。
141+
142+
`-i` / `--in-interface` / `-o` / `--out-interface`
143+
144+
: 指定数据包的输入接口或输出接口,可以是接口名称(如 `eth0`)或前缀通配符(如 `eth+`)。
145+
146+
由于 Netfilter 的结构和设计考虑,`-i`(输入接口)和 `-o`(输出接口)这两个匹配选项在不同阶段的可用性有所不同:
147+
148+
| 阶段 | 可以使用 `-i` | 可以使用 `-o` |
149+
| :---------: | :--------------------------------------: | :---------------------------------------------------: |
150+
| PREROUTING | :fontawesome-solid-check:{: .limegreen } | :fontawesome-solid-xmark:{: .orangered } |
151+
| INPUT | :fontawesome-solid-check:{: .limegreen } | :fontawesome-solid-xmark:{: .orangered } |
152+
| FORWARD | :fontawesome-solid-check:{: .limegreen } | :fontawesome-solid-check:{: .limegreen } |
153+
| OUTPUT | :fontawesome-solid-xmark:{: .orangered } | :fontawesome-solid-check:{: .limegreen }[^output-oif] |
154+
| POSTROUTING | :fontawesome-solid-xmark:{: .orangered } | :fontawesome-solid-check:{: .limegreen } |
152155

153156
[^output-oif]: 还记得[上文](#wikipedia-netfilter-packet-flow)为什么说 Wikipedia 的图更准确吗?
154157

155-
完整的 iptables 规则语法和选项可以参考 [iptables(8)][iptables.8][iptables-extensions(8)][iptables-extensions.8] 手册页。
158+
#### 动作 {#iptables-jump}
159+
160+
若一个数据包满足某条规则的所有匹配条件,就会进执行该规则的目标(`-j` / `-g` 参数)。目标可以是内置目标(如 ACCEPT、DROP、REJECT 等),也可以是用户自定义链的名称(跳转至自定义链继续处理)。
161+
162+
`-j` / `--jump``-g` / `--goto` 的区别是,当跳转到自定义链后,`-j` 会在自定义链处理完毕后返回到原链继续处理,而 `-g` 则不会返回原链,视作原链已完成处理。可以类比在 shell 中执行命令时的 `source`(对应 `-j`)和 `exec`(对应 `-g`)的区别。
163+
164+
其中,内置目标包括:
165+
166+
- ACCEPT:接受数据包,允许其继续传输。
167+
- DROP:丢弃数据包,不发送任何响应。
168+
- REJECT:拒绝数据包,并发送响应给对端(默认响应为 ICMP port unreachable)。
169+
170+
其他常用的、由扩展模块提供的目标包括:
171+
172+
- DNAT (REDIRECT) / SNAT (MASQUERADE):用于网络地址转换(NAT),分别用于更改数据包的目的地址和源地址。
173+
174+
其中 REDIRECT 和 MASQUERADE 分别是 DNAT 和 SNAT 的特殊形式,用于将数据包的目的地址和源地址改写为对应网卡上的地址。
175+
176+
- LOG:记录数据包信息到系统日志,通常与其他目标结合使用。
177+
- MARK:为数据包打上防火墙标记(firewall mark),通常与路由策略结合使用。
178+
- CONNMARK:为数据包对应的 conntrack 连接打上标记,或从连接中恢复标记。
179+
180+
每条内置链都有一个**默认策略**`-P` / `--policy`),当数据包经过该链但未匹配到任何规则时,会由该默认策略处理。默认策略可以只能是 ACCEPT、DROP 或 REJECT。
181+
182+
!!! example "例:科大镜像站上限制 80 / 443 端口并发连接数"
183+
184+
```shell
185+
iptables -A LIMIT \
186+
-p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN \
187+
-m multiport --dports 80,443 \
188+
-m connlimit --connlimit-above 12 --connlimit-mask 29 --connlimit-saddr \
189+
-j REJECT --reject-with tcp-reset
190+
```
191+
192+
这条命令的理解方式如下:
193+
194+
- `iptables -A LIMIT`:将规则追加(`-A`)到名为 LIMIT 的链中,该规则只会对 IPv4 数据包生效。IPv6 防火墙规则需要使用 `ip6tables`。
195+
196+
LIMIT 是我们自定义的一条链,在 INPUT 阶段调用,负责执行类似的限流规则。
197+
198+
- `-p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN`:匹配 TCP 协议的数据包,且匹配仅有 SYN 标志位被设置的数据包(即新连接请求)。
199+
- 等价的写法是 `-p tcp --syn`
200+
- 另一个(几乎)等价的写法是 `-m conntrack --ctstate NEW`,该写法事实上调用了连接跟踪模块,匹配将要建立新连接的数据包。
201+
- `-m multiport --dports 80,443`:调用 `multiport` 模块,匹配目的端口为 80 或 443 的数据包。
202+
- `-m connlimit --connlimit-above 12 --connlimit-mask 29 --connlimit-saddr`:调用 `connlimit` 模块,匹配来自同一子网(掩码长度 29,即每 8 个 IP 地址为一个子网)且当前已建立连接数超过 12 的数据包。
203+
- `-j REJECT --reject-with tcp-reset`:目标为 REJECT,即主动拒绝匹配的数据包,并发送 TCP RST 响应给对端。
156204

157205
### iptables 表 {#iptables-tables}
158206

0 commit comments

Comments
 (0)