Obtaining and interpreting routing tables on Linux
This post describes how to obtain and interpret the routing table of your system on Linux. A routing table is a set of rules that specify how network packets are routed based on their destination IP addresses.
To understand this post, you should be familiar with two concepts: the CIDR notation, which is used to specify IP subnetworks in the format <network-prefix>/<netmask-length>
, and the longest prefix match algorithm. If you're not familiar with them, please take the time to read the linked articles before proceeding. While our examples will focus on IPv4 networks, all the concepts we go over apply to IPv6 networks as well.
On Linux, there are two commands that are typically used for obtaining routing table information: route
and ip
. This post will use the ip
command because its output is easier to interpret than the output of route
. To display the routing table of your system with the ip
command, open a terminal and run:
ip route show
The output will depend on your network configuration. Here is an example that is very common for devices connected to a wireless router in home networks:
default via 192.168.1.1 dev wlan0
192.168.1.0/24 dev wlan0 proto kernel scope link src 192.168.1.100
Let's interpret the output above, starting with the second line. This line states that packets sent to any IP address within the subnetwork 192.168.1.0/24
must be sent through the network interface wlan0
(a wireless network interface) with 192.168.1.100
as the source IP address, which in this case is the IP address assigned to wlan0
via DHCP. In addition, proto kernel
shows that this entry in the routing table was created by the kernel during autoconfiguration, while scope link
expresses that the destination IP addresses within 192.168.1.0/24
are valid only on the device wlan0
.
The first line states that the default route for any packet (i.e., the route taken by a packet when no other route applies) is through the network device wlan0
via the default gateway (the router), which has the IP address 192.168.1.1
. Figure 1 illustrates this network scheme.
192.168.1.0/24
. The
external IP address of the router (the one visible to the Internet)
is omitted. The ip
command is highly flexible regarding its input parameters. You can enter them partially, and ip
will autocomplete them internally. To clarify, all of the commands below are equivalent:
ip r s
ip r show
ip ro sh
ip route show
A complex example: VPN routing
When you connect to a virtual private network (VPN), your network traffic is routed through an encrypted tunnel to the VPN server. As an example, let's analyze how OpenVPN accomplishes this. Consider what happens when the user of the laptop shown in figure 1 connects to an OpenVPN server. First, a virtual network interface (usually named tun0
) is created. Routes are then added to the routing table to direct all traffic through this virtual interface, where packets are encrypted and sent via the (physical) interface wlan0
to the OpenVPN server. Figure 2 illustrates a summary of this setup.
Below is a potential routing table for the OpenVPN client after it connects to the OpenVPN server:
0.0.0.0/1 via 192.168.254.9 dev tun0
default via 192.168.1.1 dev wlan0
95.91.22.94 via 192.168.1.1 dev wlan0
128.0.0.0/1 via 192.168.254.9 dev tun0
192.168.1.0/24 dev wlan0 proto kernel scope link src 192.168.1.100
192.168.254.0/24 via 192.168.254.9 dev tun0
192.168.254.9 dev tun0 proto kernel scope link src 192.168.254.10
Covering all the details of this routing table would be tedious, so we will concentrate on the most relevant aspects. The second and fifth lines are identical to those in the routing table shown earlier, meaning the default route and the route for the local network remain unchanged. On the other hand, the first and fourth lines introduce two new routes that significantly alter the routing rules: packets with destination addresses matching either 0.0.0.0/1
or 128.0.0.0/1
are now routed through tun0
, with 192.168.254.9
as the gateway IP address.
The catch here is that 0.0.0.0/1
and 128.0.0.0/1
match packets with destination IP addresses where the first bit equals 0
and 1
respectively. Combined, they match all packets not matched by other routes. The fifth line will still apply for all IP addresses within the range 192.168.1.0/24
(so communicating with devices in the local network will still be possible), but since the first bit of a packet will always be either 0
or 1
, the default route will never be applied. In other words, OpenVPN creates two routes that collectively match every packet that is not addressed to a device in the local network; these packets are then routed to the interface tun0
. From there, packets are encrypted and sent to 95.91.22.94
(the OpenVPN server). Finally, the route specified on the third line directs the packets to be sent out through the physical interface wlan0
via the gateway 192.168.1.1
.
The last two lines are also important. They exist due to the fact that OpenVPN creates the virtual tun0
interface in point-to-point mode, meaning this interface functions as if directly connected to another endpoint: the OpenVPN server. The server establishes a virtual local network 192.168.254.0/24
and assigns IP addresses from this pool to each endpoint of the connection. As shown on the last line, the IP address assigned to the client is 192.168.254.10
, with 192.168.254.9
being the IP address of the server endpoint. This can be seen more clearly by running:
ip addr show dev tun0
The output provides a clear demonstration of the point-to-point connection mentioned in the previous paragraph:
21: tun0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN group default qlen 100
link/none
inet 192.168.254.10 peer 192.168.254.9/32 scope global tun0
valid_lft forever preferred_lft forever