Localhost is (sometimes) a network

August 19, 2016

Everyone knows localhost, 127.0.0.1, the IP(v4) address of every machine's loopback network. If you're talking to 127.0.0.1, you're talking to yourself (machine-wise). Many of us (although not all) know that localhost is not just a single IP address; instead, all of 127.*.*.* (aka 127/8) is reserved as the loopback network. ifconfig will tell you about this on most machines:

lo0: flags=[...]
        inet 127.0.0.1 netmask ff000000 

You don't see that many 0's in a netmask all that often.

One of the tricks that you can play here is to give your loopback network more 127.* IP aliases. Why would you want that? Well, suppose that you have two things that both want to run localhost web servers. With 127.* IP aliases, one can be http://127.0.0.1/ and the other can be http://127.0.0.2/, and both can be happy. Localhost IP aliases can also be a convenient way to invent additional source addresses for testing. Need to connect to something on the same machine from ten different source IPs? Just add 127.0.100.1 through 127.0.100.10, then have your software rotate among them as the source addresses. It's all still loopback traffic, so all of the usual guarantees apply; it just has some different IPs involved.

Sometimes, though, we mean that loopback is a network in a more literal way. Specifically, on Linux:

bash
$ ping 127.0.$(($RANDOM % 256)).$(($RANDOM % 256))
PING 127.0.251.170 (127.0.251.170) 56(84) bytes of data.
64 bytes from 127.0.251.170: icmp_seq=1 ttl=64 time=0.055 ms
[...]

On at least FreeBSD, OpenBSD, and OmniOS, this will fail in various ways. On Linux, it works. Through black magic, you don't have to add additional 127.* IP aliases in order to use those addresses; although not explicitly declared anywhere as existing, they are just there, all 16,777,215 or so of them. The various localhost IPs are all distinct from each other as usual, so a service listening on some port on 127.0.0.1 can't be reached at that port on 127.0.0.2. You just don't have to explicitly create 127.0.0.2 before you can start using it, either to have a service listen on it or to have a connection use that as its source address.

(And anything that listens generically can be reached on any 127.* address. You can ssh to these random localhost IPs, for example.)

PS: Before I tested it as part of writing this entry, I thought that the Linux behavior was how all Unixes worked. I was a bit surprised to find otherwise, partly because it makes the Linux behavior (much) more odd. It is kind of convenient, though.


Comments on this page:

By danielkza at 2016-08-19 09:28:32:

On Linux, it works. Through black magic, you don't have to add additional 127.* IP aliases in order to use those addresses; although not explicitly declared anywhere as existing, they are just there, all 16,777,215 or so of them.

That black magic is a route entry with destination 127.0.0.0/8 to the loopback interface. It doesn't show up with `route` or `ip route` because it doesn't live in the main route table, but in the `local` table.

   $ ip rule show
   0:	from all lookup local
   32766:	from all lookup main
   32767:	from all lookup default
   $ ip route
   default via 192.168.1.1 dev wlp5s0  proto static  metric 600 
   172.17.0.0/16 dev docker0  proto kernel  scope link  src 172.17.0.1 linkdown 
   192.168.1.0/24 dev wlp5s0  proto kernel  scope link  src 192.168.1.110  metric 600 
   192.168.122.0/24 dev virbr0  proto kernel  scope link  src 192.168.122.1 linkdown
   $ ip route show table local
   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
   ...
Written on 19 August 2016.
« A surprising missing Unix command: waiting until a time is reached
My current Go autocompletion setup in GNU Emacs »

Page tools: View Source, View Normal.
Search:
Login: Password:

Last modified: Fri Aug 19 01:48:52 2016
This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.