Today we will learn about loopback addresses that can be reached from the outside via routing. This is useful for running services on a router
In a previous post, I talked about the loopback interface and how we can locally bind services to any address in the range
127.0.0.1-127.255.255.254. This is useful if
127.0.0.1 is already in use on a particular port.
The main advantages of loopback addresses are:
- Adding additional addresses without the need to add extra interfaces
- Better availability of services, as long as you have a route to the loopback address, the service will stay up.
- Can hide the presence of services to an attacker probing the addresses of connected interfaces.
Adding a loopback address
sudo ip address add 10.32.16.8 dev lo
Accessing it from the outside
We can't yet ping it from the outside. Why? Because none of the outside hosts have a route to it.
So let's connect to my router and add a route
sudo ip route add to 10.32.16.8 via $DESKTOP_IP
Now any host on my network should be able to reach
10.32.16.8 providing it uses the above router as its default gateway.
On my router, we can add
iptables rules to restrict forwarding to the address.
A simple example will be that only hosts on the
eth1 interface can access the loopback address.
sudo iptables -I FORWARD ! -i eth1 -d 10.32.16.8 -j DROP
We can also do this by source address if desired.
What about locking it down on my desktop?
There are a number of ways we may wish to lock it down on my desktop (the host on which I created the loopback address)
First let's create a chain for it.
sudo iptables -N LOOPBACK_ADDR sudo iptables -I INPUT --dst 10.32.16.8 -j LOOPBACK_ADDR
Give a default action for the chain
sudo iptables -A LOOPBACK_ADDR -j DROP
We can add rules to whitelist traffic to the loopback address
Restrict to eth1 interface
sudo iptables -I LOOPBACK_ADDR -i eth0 -j ACCEPT
Restrict access on the loopback address only to a particular port
sudo iptables -I LOOPBACK_ADDR -p tcp --dport 80 -j ACCEPT
Allow ICMP ping
sudo iptables -I LOOPBACK_ADDR -p icmp --icmp-type echo-request -j ACCEPT
NAT + Docker
I frequently use loopback addresses as the external endpoint for services running inside Docker containers
For example, we want a Ghost blog to be accessible on
We can use the following command
$ docker run -p 10.32.16.8:80:2368 docker.io/ghost:latest
We don't want any services on the host itself to be accessible on that address. The rules for redirecting traffic to the docker container are in the
nat iptable, which is evaluated before the
filter table (which as the name suggests, is for filtering traffic to the host).;
So if we run
$ sudo iptables -I INPUT -d 10.32.16.8 -j DROP
We will still be able to access the Ghost blog at that address, but won't, for example, be able to access the hosts ssh service on that address.
Better availability of services
Suppose we have a Router with the following interfaces:
lo 127.0.0.1/8 lo 10.53.53.53/32 eth0 10.10.0.1/24 eth1 10.10.1.1/24
We want to run a DNS server on the Router. Normally, we would have to do one of the following:
- Bind the DNS server to
- Have two listening sockets for
Both are kind of disadvantageous. With the first, it's generally bad security to bind to all interfaces, and with the second, with DHCP we will need to give different dns server addresses for each interface.
Instead, we bind the DNS server to the loopback address. Now as long as we are able to access the router, we will be able to access the DNS server at the address
There is an additional security benefit here, we can make our DNS server somewhat hidden. A rogue host on the lan may try probing
10.10.0.1 as its the default gateway address, but they won't find the DNS server because it's listening on the loopback address. There is basically no way to know there's a DNS server running unless you know to try
Another neat trick
Keeping with the example of the LAN DNS. Suppose we have a DNS server running on a LAN host, as well as a couple of additional DNS servers to serve as backup.
All the DNS servers have a loopback address of
We have as follows:
10.10.0.53 - primary dns server 10.10.1.53 - backup dns server
On the Router we do the following
sudo ip route add to 10.53.53.53 via 10.10.0.53 metric 1 sudo ip route add to 10.53.53.53 via 10.10.1.53 metric 2
I wish to perform maintenance on the primary server and thus need to fallback to the backup.
We run the following command on the router
sudo ip route del to 10.53.53.53 via 10.10.0.53 metric 1
Now connections to
10.53.53.53 will route to 10.10.1.53 (the backup server) rather than the primary
The cool thing is I can change the DNS server for my lan without having to tell everyone to change their DNS server
Loopback source addresses
Remember, any destinations you connect to need to have the loopback address inside their routing table.
For this example, we will work on my Router because that is the default gateway on my network (therefore any hosts on my network will already have a route to any loopback address on the router)
Let's create a new loopback address on the router
sudo ip address add 192.0.2.69/32 dev lo
Now we run the following command
sudo ip route change 10.10.0.0/24 src 192.0.2.69
Now whenever the router connects to anything in the network
10.10.0.0/24 its source address will show up as
To prove it, on the router, let's connect to the https server on my raspberry pi
telnet 10.10.0.80 443
At the same time, on the RasPi we look at our socket statistics
$ ss -lt -o state established Recv-Q Send-Q Local Address:Port Peer Address:Port 0 0 10.10.0.80:https 192.0.2.69:51556