Problem
I am experiencing some rather odd behavior where a seemingly unrelated default gateway route is having unexpected side-effects. I managed to replicate this issue with a minimal example. The aim here is mostly educational and I stumbled upon this while experimenting with a more complex scenario. In short, I am managing to connect to a web server on 192.168.0.3 when I believe I should not.
My laptop is connected to my home network using WiFi (192.168.0.0/24 network). The routing table is listed below:
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
Both curl 192.168.0.3 and curl --interface wlp2s0 192.168.0.3 currently work and give the following response:
<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>
Now, I proceed to remove all the routes related to the 192.168.0.0/24 network such that the remaining routes are:
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
Additionally, ip route get with and without binding to an interface are shown below:
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
Running curl 192.168.0.3 gives curl: (7) Couldn't connect to server and running curl --interface wlp2s0 192.168.0.3 gives nothing (curl is blocked). Here's a snippet of what strace shows:
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)
This is fine and what I was expecting, i.e., laptop shouldn't be able to reach 192.168.0.3.
Now here is the strange part. If I add a dummy default gateway (say the docker0 interface via a random address) such that my routing table is as follows:
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
Running curl 192.168.0.3 fails but running curl --interface wlp2s0 192.168.0.3 succeeds with the previous HTML reply.
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
I researched aboutSO_BINDTODEVICE and found out that it still should be obeying the routing table. Why does the addition of a default gateway through a different interface via a random address make curl --interface wlp2s0 192.168.0.3 succeed?
Address Details
The following command lists the addresses associated with the interfaces. I have checked that after each command executed above, the result of this command is always the same.
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
In summary 192.168.0.210 is this laptop, 192.168.0.3 is another machine on the network hosting a web server and 192.168.0.1 is the default gateway (my router).
Environment
I am running Linux Mint. Here is some info.
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