问题
我遇到了一些相当奇怪的行为,其中看似无关的默认网关路由产生了意想不到的副作用。我设法用一个最小的例子来复制这个问题。这里的目的主要是教育性的,我在尝试更复杂的场景时偶然发现了这一点。简而言之,当我认为不应该连接到192.168.0.3上的 Web 服务器时,我却设法连接到了。
我的笔记本电脑使用 WiFi( 192.168.0.0/24网络)连接到我的家庭网络。路由表如下:
kevin@kevin-UX305LA:~$ ip route
default via 192.168.0.1 dev wlp2s0 proto dhcp metric 600
169.254.0.0/16 dev wlp2s0 scope link metric 1000
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 linkdown
192.168.0.0/24 dev wlp2s0 proto kernel scope link src 192.168.0.210 metric 600
和目前curl 192.168.0.3
都curl --interface wlp2s0 192.168.0.3
在工作并给出以下响应:
<html>
<head><title>301 Moved Permanently</title></head>
<body>
<center><h1>301 Moved Permanently</h1></center>
<hr><center>nginx/1.25.2</center>
</body>
</html>
现在,我继续删除与192.168.0.0/24网络相关的所有路由,以便其余路由为:
kevin@kevin-UX305LA:~$ sudo ip route del default via 192.168.0.1
kevin@kevin-UX305LA:~$ sudo ip route del 192.168.0.0/24
kevin@kevin-UX305LA:~$ ip route
169.254.0.0/16 dev wlp2s0 scope link metric 1000
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 linkdown
此外,ip route get
有和没有绑定到接口的情况如下所示:
kevin@kevin-UX305LA:~$ ip route get 192.168.0.3
RTNETLINK answers: Network is unreachable
kevin@kevin-UX305LA:~$ ip route get oif wlp2s0 192.168.0.3
192.168.0.3 dev wlp2s0 src 192.168.0.210 uid 1000
cache
运行curl 192.168.0.3
会给出结果curl: (7) Couldn't connect to server
,运行curl --interface wlp2s0 192.168.0.3
不会给出任何结果(curl 被阻止)。以下是 strace 显示的片段:
setsockopt(5, SOL_SOCKET, SO_BINDTODEVICE, "wlp2s0\0", 7) = 0
connect(5, {sa_family=AF_INET, sin_port=htons(80), sin_addr=inet_addr("192.168.0.3")}, 16) = -1 EINPROGRESS (Operation now in progress)
这很好,符合我的预期,即笔记本电脑应该无法到达192.168.0.3。
现在这是奇怪的部分。如果我添加一个虚拟默认网关(例如通过随机地址的docker0接口),则我的路由表如下:
kevin@kevin-UX305LA:~$ sudo ip route add default via 172.17.0.2
kevin@kevin-UX305LA:~$ ip route
default via 172.17.0.2 dev docker0 linkdown
169.254.0.0/16 dev wlp2s0 scope link metric 1000
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 linkdown
运行curl 192.168.0.3
失败,但运行curl --interface wlp2s0 192.168.0.3
成功并显示先前的 HTML 回复。
kevin@kevin-UX305LA:~$ curl 192.168.0.3
curl: (7) Failed to connect to 192.168.0.3 port 80 after 3068 ms: No route to host
kevin@kevin-UX305LA:~$ ip route get 192.168.0.3
192.168.0.3 via 172.17.0.2 dev docker0 src 172.17.0.1 uid 1000
cache
kevin@kevin-UX305LA:~$ curl --interface wlp2s0 192.168.0.3
<html>
<head><title>301 Moved Permanently</title></head>
<body>
<center><h1>301 Moved Permanently</h1></center>
<hr><center>nginx/1.25.2</center>
</body>
</html>
kevin@kevin-UX305LA:~$ ip route get oif wlp2s0 192.168.0.3
192.168.0.3 dev wlp2s0 src 192.168.0.210 uid 1000
cache
我研究了一下SO_BINDTODEVICE
,发现它仍然应该遵守路由表。为什么通过随机地址通过不同接口添加默认网关会curl --interface wlp2s0 192.168.0.3
成功?
详细地址
以下命令列出与接口关联的地址。我检查过,执行上面的每个命令后,该命令的结果总是相同的。
kevin@kevin-UX305LA:~$ ip -br addr
lo UNKNOWN 127.0.0.1/8 ::1/128
wlp2s0 UP 192.168.0.210/24 fe80::7a03:3420:b8b0:4db7/64
docker0 DOWN 172.17.0.1/16
总之,192.168.0.210是这台笔记本电脑,192.168.0.3是网络上托管 Web 服务器的另一台计算机,192.168.0.1是默认网关(我的路由器)。
环境
我正在运行 Linux Mint。这是一些信息。
kevin@kevin-UX305LA:~$ uname -a
Linux kevin-UX305LA 5.15.0-84-generic #93-Ubuntu SMP Tue Sep 5 17:16:10 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux
kevin@kevin-UX305LA:~$ lsb_release -a
No LSB modules are available.
Distributor ID: Linuxmint
Description: Linux Mint 21.2
Release: 21.2
Codename: victoria