我有一个多宿主设置,有两个上游提供商。我想限制某些连接仅使用一个提供商 - 即本地传出连接。因此,我制作了一个自定义路由表,其中包含一个直接连接的网络路由和一个默认路由:
$ ip route show table 2
default via 5.1.0.1 dev upstream_b
5.1.0.0/16 dev upstream_b scope link src 5.1.0.2
接下来,我使用 iptables 中的选择器为某些连接添加 fwmark,并使用 ip-rule 覆盖路由表选择:
# for output traffic
# restore packet mark from connection mark
iptables --table mangle --append OUTPUT -j CONNMARK --restore-mark
# for !0 packet marks bail out
iptables --table mangle --append OUTPUT -m mark ! --mark 0 -j ACCEPT
# set packet mark
iptables --table mangle --append OUTPUT -m cgroup --cgroup 0x00010002 -j MARK --set-mark 0x2
# save packet mark to connection mark
iptables --table mangle --append OUTPUT -j CONNMARK --save-mark
# for input traffic restoring mark from connmark
iptables --table mangle --append PREROUTING -j CONNMARK --restore-mark
# adding policy forwarding
ip rule add from all fwmark 2 table 2
因此,对于某些进程(在指定的net_cls
cgroup 中),其传出连接将符合连接标记规则,然后应通过upstream_b
接口进行路由。
但这不起作用(对于放入 net_cls cgroup 的 bash shell):
$ curl --resolve ifconfig.co:80:188.113.88.193 -v http://ifconfig.co
* Added ifconfig.co:80:188.113.88.193 to DNS cache
* Rebuilt URL to: http://ifconfig.co/
* Hostname ifconfig.co was found in DNS cache
* Trying 188.113.88.193...
* Immediate connect fail for 188.113.88.193: Network is unreachable
* Closing connection 0
curl: (7) Couldn't connect to server
main
当路由表没有默认路由(即没有到 ifconfig.co 的路由)时,就会发生上述结果。
但这并不是全部。由于我使用的是多宿主设置,因此通常会有一个 ECMP 路由来平衡通过两个提供商的流量。对于上述测试,我得到了一个有趣的结果。tcp-syn 包到达了正确的接口,但源地址不正确(来自另一个接口)。
因此,综合这些观察,首先,根据路由表做出路由决策main
(因此,网络无法访问)。接下来,在进一步处理包时,它会触发标记规则,然后重新路由(基于自定义路由表)。但源地址已在第一个路由决策中设置,因此这里不会进行更正。
我对问题起源的理解正确吗?
我需要对一些本地进程强制执行非默认路由表,但上述方法不起作用。执法能否完成?例如,是否可以触发源地址重新计算?
编辑。考虑下图(此处的内核版本不是那么现代,但仍然有用;该图来自http://open-source.arkoon.net/kernel/kernel_net.png):
看起来,第一个路由决策和包源地址选择确实是在任何 iptables 规则启动之前执行的(见右下角)。