What is the routing table in Linux?
You may have used the IP address
You may not have used
What is this?
Try it out by listening on this IP address:
$ nc -l 127.0.0.2 1234
Now, from the same machine, you can open a TCP connection, and have a conversation:
$ nc 127.0.0.2 1234 hello! hey
This was new to me!
How is this working?
Let’s see what’s going on at the IP packet level
$ sudo tcpdump -n -i lo tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes 00:41:53.550184 IP 127.0.0.1.39070 > 127.0.0.2.1234: Flags [S], seq 273312456, win 43690, options [mss 65495,sackOK,TS val 633989 ecr 0,nop,wscale 6], length 0 00:41:53.550192 IP 127.0.0.2.1234 > 127.0.0.1.39070: Flags [S.], seq 858890764, ack 273312457, win 43690, options [mss 65495,sackOK,TS val 633989 ecr 633989,nop,wscale 6], length 0 00:41:53.550200 IP 127.0.0.1.39070 > 127.0.0.2.1234: Flags [.], ack 1, win 683, options [nop,nop,TS val 633989 ecr 633989], length 0
All traffic happens over the
lo interface, or “loopback”.
I was aware that packets to
127.0.0.1 would go to the loopback interface,
but it seems that packets to
127.0.0.2 also go to the loopback interface.
127.0.0.1 is still used as the IP address opening the connection,
127.0.0.1 is used in the response packets.
How does this happen?
Linux has some procedures to determine which network interface should get a packet.
This procedure is called “routing”.
Linux determines the route based on the destination IP address of the packet.
The procedure uses the Linux “routing policy database”,
which is a list of rules.
We can see that list with the
$ ip rule show 0: from all lookup local 32766: from all lookup main 32767: from all lookup default
Linux visits each of these rules in order
until one of them determines a route.
So Linux first runs the rule
from all lookup local.
This says to look in the table called
We can see that table with another
$ ip route show table local broadcast 10.0.2.0 dev eth0 proto kernel scope link src 10.0.2.15 local 10.0.2.15 dev eth0 proto kernel scope host src 10.0.2.15 broadcast 10.0.2.255 dev eth0 proto kernel scope link src 10.0.2.15 broadcast 127.0.0.0 dev lo proto kernel scope link src 127.0.0.1 local 127.0.0.0/8 dev lo proto kernel scope host src 127.0.0.1 local 127.0.0.1 dev lo proto kernel scope host src 127.0.0.1 broadcast 127.255.255.255 dev lo proto kernel scope link src 127.0.0.1
Our packet with destination
127.0.0.2 matches the following route:
local 127.0.0.0/8 dev lo proto kernel scope host src 127.0.0.1
127.0.0.2 matches the subnet
(So we could even have used the address
dev lo says, “put this packet on the loopback device.”
I wrote this because I felt like it. This post is not associated with my employer. This site is hosted by Netlify (who are great, but I'm not associated with them either).