我的 Linux 系统上有多个网络接口。有些是物理的(eth0
等等),有些是虚拟的(tun0
等等,由 OpenVPN 创建)。
是否可以检查是否可以通过给定接口访问给定主机(IP 地址)?
ping
支持-I
选择接口的选项。但是ping -I tun0 1.1.1.1
不起作用:我没有收到任何数据包。这很令人惊讶,因为tun0
如果我在路由表中将该接口设置为网关,我可以通过 到达 1.1.1.1 。
我还能如何检查 1.1.1.1 是否可以通过 eg 到达tun0
,而不更改该路由的主机网关?
更多细节:我正在使用这个系统通过不同的接口将整个网络的流量转发到互联网。有时会停止提供互联网访问,我的目标是编写一个脚本,在发生这种情况时更改接口。如果您有关于如何更好地进行设置的良好指南/教程,我很高兴阅读它们。
以下是一些显示我的系统状态的命令的输出(为了隐私而进行了一些修剪和编辑):
# ping -c1 -W1 1.1.1.1 -Ieth0 | tail -n2
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 8.997/8.997/8.997/0.000 ms
# ping -c1 -W1 1.1.1.1 -Itun0 | tail -n2
1 packets transmitted, 0 received, 100% packet loss, time 0ms
# ping -c1 -W1 1.1.1.1 -Itun1 | tail -n2
1 packets transmitted, 0 received, 100% packet loss, time 0ms
# ip -br link
lo UNKNOWN 00:00:00:00:00:00 <LOOPBACK,UP,LOWER_UP>
eth0 UP 01:23:45:67:89:ab <BROADCAST,MULTICAST,UP,LOWER_UP>
tun1 UNKNOWN <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP>
tun0 UNKNOWN <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP>
# ip -4 addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
inet 192.168.0.1/24 brd 192.168.0.255 scope global eth0
valid_lft forever preferred_lft forever
inet 192.168.1.1/24 brd 192.168.1.255 scope global eth0
valid_lft forever preferred_lft forever
12: tun1: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UNKNOWN group default qlen 100
inet 172.16.1.8 peer 172.16.1.9/32 scope global tun1
valid_lft forever preferred_lft forever
13: tun0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UNKNOWN group default qlen 100
inet 172.16.0.6 peer 172.16.0.5/32 scope global tun0
valid_lft forever preferred_lft forever
# ip route
10.0.0.0/22 via 172.16.0.5 dev tun0
2.3.4.5 via 192.168.1.2 dev eth0
172.16.0.0/24 via 172.16.0.5 dev tun0
172.16.0.5 dev tun0 proto kernel scope link src 172.16.0.6
172.16.1.0/24 via 172.16.1.9 dev tun1
172.16.1.9 dev tun1 proto kernel scope link src 172.16.1.8
192.168.0.0/16 via 172.16.1.9 dev tun1
192.168.0.0/24 dev eth0 proto kernel scope link src 192.168.0.1
192.168.1.0/24 dev eth0 proto kernel scope link src 192.168.1.1
1.2.3.4 via 192.168.1.2 dev eth0
# ip rule
0: from all lookup local
32766: from all lookup main
32767: from all lookup default
40000: from 192.168.0.0/28 lookup physical
500000: from all iif lo lookup physical
600000: from 192.168.0.4 lookup physical
900000: from all lookup fallback
# ip -details link show dev tun0
13: tun0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UNKNOWN mode DEFAULT group default qlen 100
link/none promiscuity 0
tun numtxqueues 1 numrxqueues 1
# ip -details link show dev tun1
12: tun1: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UNKNOWN mode DEFAULT group default qlen 100
link/none promiscuity 0
tun numtxqueues 1 numrxqueues 1
# iptables-save -c
# Generated by iptables-save v1.6.2 on Tue Sep 5 10:15:50 2023
*filter
:INPUT ACCEPT [59898142:66144679517]
:FORWARD ACCEPT [82206554:78274304851]
:OUTPUT ACCEPT [26945751:6646653799]
COMMIT
# Completed on Tue Sep 5 10:15:50 2023
# Generated by iptables-save v1.6.2 on Tue Sep 5 10:15:50 2023
*nat
:PREROUTING ACCEPT [2568037:216846789]
:INPUT ACCEPT [2278788:177840950]
:OUTPUT ACCEPT [853479:59465416]
:POSTROUTING ACCEPT [0:0]
[1133282:97570449] -A POSTROUTING -j MASQUERADE
COMMIT
# Completed on Tue Sep 5 10:15:50 2023
# sudo iptables -t nat -S
-P PREROUTING ACCEPT
-P INPUT ACCEPT
-P OUTPUT ACCEPT
-P POSTROUTING ACCEPT
-A POSTROUTING -j MASQUERADE
# ip route show table default
# ip route show table physical
default via 192.168.1.2 dev eth0 proto static
# ip route show table fallback
default via 172.16.0.5 dev tun0 metric 5
default via 172.16.1.9 dev tun1 metric 10
答案1
设置
OP 的策略路由设置并不常见:
没有任何规则可以凌驾于规则之上主要的桌子
相反,主表中没有默认路由,
并评估附加规则后主表
主机实际重要的路由规则是
500000: from all iif lo lookup physical
因为这是主机(本地节点而不是转发流量)的第一条规则,它将匹配 INADDR_ANY(又名地址 0.0.0.0,将匹配 0.0.0.0/0 路由),因此它将用于任何(TCP、 UDP、ICMP ...)客户端查询不绑定到地址或接口,选择以太网0。
对使用共享同一广播域的两个网络完成的单臂路由没有评论以太网0,与问题无关。
我可以想象这个设置的主要目的是允许来自的流量来回tun1
路由以tun0
到达互联网,而无需与主机自己的流量进行(太多)交互。我认为应该有更简单或更标准的方法来做同样的事情,但这就是设置。
检测路由问题
内核路由堆栈的每个选择都可以通过以下命令进行检查ip route get
:
ip route get
获取单一路线
该命令获取到目的地的单个路由并完全按照内核所看到的方式打印其内容。
当绑定到接口时(使用SO_BINDTODEVICE
),可以通过附加选择器查询强制路由效果oif
。
发射数据包:
# ip route get oif tun0 to 1.1.1.1
1.1.1.1 via 172.16.0.5 dev tun0 table fallback src 172.16.0.6 uid 0
cache
既然有路线,tcp转储应该看到发出的数据包屯0界面。
返回路径,乍一看,也应该工作:
# ip route get from 1.1.1.1 iif tun0 to 172.16.0.6
local 172.16.0.6 from 1.1.1.1 dev lo table local
cache <local> iif tun0
和tcp转储还将捕获返回数据包。
但如果rp_filter=1
已就位使用严格反向路径转发(SRPF)则改为:
# ip route get from 1.1.1.1 iif tun0 to 172.16.0.6
RTNETLINK answers: Invalid cross-device link
回复数据包,虽然仍然被捕获tcp转储将被路由堆栈丢弃:平失败。
因此,我只能假设,rp_filter=1
在不常见的路由设置中,此类路由被视为非对称路由,因为它期望返回路径与500000: from all iif lo lookup physical
使用的路由相匹配以太网0。正如该数据包所示屯0而不是以太网0,它未通过 SRPF 验证。事实是平当路由堆栈使用 SRPF 验证时,进程确实绑定到接口是无关紧要的返回流量。
修复它
oif tun0
为了在保持 SRPF 的同时发挥作用,应添加一条与最终由172.16.0.6选择的源地址匹配的路由规则。它的偏好可以是任何 < 500000 的值(之后以太网0会被选择)来满足SRPF算法的实现。
ip rule add from 172.16.0.6 lookup fallback
现在得到(仍然是rp_filter=1
):
# ip route get from 1.1.1.1 iif tun0 to 172.16.0.6
local 172.16.0.6 from 1.1.1.1 dev lo table local
cache <local> iif tun0
含义:接受并接收数据包以供本地使用(通过ping
命令)。
这也允许在不绑定到接口的情况下工作,而只绑定到地址:
ping -I 172.16.0.6 1.1.1.1
确实,之前有:
# ip route get from 172.16.0.6 to 1.1.1.1
1.1.1.1 from 172.16.0.6 via 192.168.1.2 dev eth0 table physical uid 0
cache
不会使用隧道。
但是之后:
# ip route get from 172.16.0.6 to 1.1.1.1
1.1.1.1 from 172.16.0.6 via 172.16.0.5 dev tun0 table fallback uid 0
cache
或者,为了避免更改路由规则,可以设置要使用的隧道接口,而不是上述规则松散的RPF哪个优先通过SRPF:
sysctl -w net.ipv4.conf.tun0.rp_filter=2
这使得 RPF 检查能够通过,尽管存在(假定的)非对称路由。这使得 ping 可以在ping -I tun0 1.1.1.1
没有任何其他路由更改的情况下工作(但不再使用了ping -I 172.16.0.6 1.1.1.1
,因为以太网0像以前一样再次选择(见上文))。
同样可以用屯1。任何一个:
ip rule add from 172.16.1.8 lookup fallback
或者:
sysctl -w net.ipv4.conf.tun1.rp_filter=2