Skip to content

Commit 12f3b98

Browse files
committed
routing: Add source based routing with forwarding
1 parent a2c33d3 commit 12f3b98

File tree

1 file changed

+54
-1
lines changed

1 file changed

+54
-1
lines changed

docs/ops/network/routing.md

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -277,4 +277,57 @@ default via 198.51.100.1 dev eth1
277277
这对于具有多张网卡或接入了多个网络的服务器尤为重要,否则可能会导致客户端无法与服务器建立连接。
278278

279279
该方法的一个局限性是,它只能为本机运行的服务(进程)提供「源进源出」的能力,无法满足通过本机转发的流量(如经过 NAT 的转发)的需求。
280-
这种需求需要结合使用防火墙对数据包的 mark、连接跟踪器(conntrack)的 connmark 标记和路由规则的 `fwmark` 匹配条件综合实现。
280+
这种需求需要结合使用数据包的防火墙标记(mark)、[连接跟踪器(conntrack)](firewall.md#conntrack)[connmark 标记](firewall.md#conntrack-mark)和路由规则的 `fwmark` 匹配条件综合实现。
281+
282+
### 源进源出 + 转发 {#source-based-routing-with-forwarding}
283+
284+
本需求的一个典型场景是,路由器具有多个上游(WAN 接口)或接入了多个运营商,同时对 LAN 侧的主机提供 NAT 转发上网功能。
285+
286+
本节内容需要结合防火墙规则和 conntrack 的知识,建议先对[防火墙](firewall.md)章节中的相关内容有初步了解。
287+
288+
使用基于源地址的路由规则只能为本机发出的数据包实现「源进源出」,而无法满足通过本机转发的流量的需求。
289+
这是因为前文的方式依赖于这项假设:建立连接的数据包的目的地址必然是对应接口上的地址,那么对于回包来说,源地址自然也是对应接口上的地址,那么基于源地址决定从哪个接口发出就能保证「源进源出」。
290+
但对于转发的数据包来说,回包的源地址不再对应到接口上了,因此源地址匹配的方式就不顶用了。
291+
292+
此时,我们可以结合使用防火墙标记(fwmark)和 conntrack 标记(connmark)来实现「源进源出」的需求。
293+
具体做法分为几个部分:
294+
295+
- 在初次确定上游接口的时候,为数据包打上对应的防火墙标记(mark),并将该标记保存到 CT 中(connmark)。
296+
- 若一个待转发的数据包(PREROUTING)匹配某条连接,那么就从 CT 中将对应的 connmark 还原到数据包上作为 fwmark。
297+
- 在路由规则中使用 `fwmark` 条件匹配对应的防火墙标记,进入对应的路由表,从而实现「源进源出」。
298+
299+
作为例子,本文假设路由器有两个 WAN 接口 `eth0``eth1`,分别指定防火墙标记为 100 和 101,那么路由规则可以这样写:
300+
301+
```shell title="ip rule"
302+
0: from all lookup local
303+
1: from all lookup main suppress_prefixlength 0
304+
3: from all fwmark 100 lookup eth0
305+
3: from all fwmark 101 lookup eth1
306+
32766: from all lookup main
307+
32767: from all lookup default
308+
```
309+
310+
然后在防火墙规则中配置打标和还原标记的规则:
311+
312+
```shell title="iptables"
313+
*mangle
314+
:PREROUTING ACCEPT [0:0]
315+
:INPUT ACCEPT [0:0]
316+
:FORWARD ACCEPT [0:0]
317+
:OUTPUT ACCEPT [0:0]
318+
:POSTROUTING ACCEPT [0:0]
319+
# 若数据包属于已建立连接,恢复 connmark 到 fwmark
320+
-A PREROUTING -j CONNMARK --restore-mark
321+
-A PREROUTING -m mark ! --mark 0 -j RETURN
322+
323+
# 初次确定上游接口,打标并保存到 conntrack
324+
-A PREROUTING -i eth0 -j MARK --set-mark 100
325+
-A PREROUTING -i eth1 -j MARK --set-mark 101
326+
-A PREROUTING -j CONNMARK --save-mark
327+
COMMIT
328+
```
329+
330+
前两条规则会尝试从 CT 中恢复 connmark 到 fwmark,如果恢复成功,那么数据包的标记就不再为零,可以直接 RETURN,避免重复打标。
331+
若标记仍为零,则表示这是一个新连接的数据包,需要根据输入接口打上对应的标记,并保存到 CT 中以备后续使用。
332+
333+
注意到,尽管打标的规则仅使用了 `-i`(输入接口)条件,对于从 LAN 侧向 WAN 侧发起的连接来说,在收到第一个回包时,输入接口自然就是对应的 WAN 接口,因此打标是正确的。

0 commit comments

Comments
 (0)