Table of Contents

Network - Enable forwarding of IPv4 network packets

To enable forwarding of IPv4 network packets, so that a machine can act as a router.

Background

A router is a machine that is connected to two or more networks and which forwards packets between those networks. The ability to act as a router is built into the Linux kernel, but for reasons of safety and security it is usually disabled by default.

Scenario

Suppose that a machine is to act as a boundary router between a local area network (connected to interface eth0) and the public Internet (accessed through interface ppp0). All machines have public IP addresses, therefore there is no need for any form of NAT.

Prerequisites

These instructions assume that the network interfaces and routing table have been configured to the point that the router can communicate with any machine on the local area network or the public Internet.

If you wish to perform any firewalling on the router then this should be done before you enable forwarding: afterwards may be too late.

Method

Add the following line to the file /etc/sysctl.conf:

/etc/sysctl.conf
net.ipv4.ip_forward=1

Ensure that there are no other lines in the file that refer to net.ipv4.ip_forward. (You may find that there is a commented-out line of the required form already in the file. If so then all you need do is uncomment it.)

Load the new setting into the kernel using the sysctl command:

sysctl -p

(This should happen automatically whenever the machine is rebooted.)

Testing

Use ping to check end-to-end connectivity from a machine on one side of the router to a machine on the other side. This should preferably be done using a numeric IP address as opposed to a domain name so that the outcome of the test does not depend on whether name resolution has been configured correctly.

Troubleshooting

Check that forwarding is switched on.

Read back the setting from the kernel using the sysctl command:

sysctl net.ipv4.ip_forward

This should give the answer:

net.ipv4.ip_forward = 1

A result of 0 probably indicates an error in /etc/sysctl.conf. Failure to return a result probably indicates that /proc has not been mounted (see below).

Check connectivity from each router interface

Use ping to check connectivity between the router and each of the machines used for the end-to-end test.

Monitor the packet flow

Use tcpdump or a similar tool to answer the following questions, stopping at the first one for which the answer is no:

  1. Does the outbound connection request reach the router?
  2. Does the router forward the request onto the other network?
  3. Does the reply reach the router?
  4. Does the router forward the reply back onto the original network?

A negative answer to questions 1 or 3 indicates a networking problem that is not associated with forwarding.

A negative answer to 2 or 4 could indicate that:

The first two of these explanations should already have been excluded by prior tests. The third should have been partially excluded, unless you have a complicated configuration with multiple routing tables, but it is worth checking to make sure. For most users, a firewall rule is the most likely explanation.

Check routing

Suppose that the internal interface of the router is eth0 with the address 192.168.0.1, the external interface is eth1 with the address 203.0.113.1, the default route is 203.0.113.2, and the internal and external addresses between which you are testing connectivity are 192.168.0.2 and 198.51.100.1 respectively.

Check how outbound packets are routed with the command:

ip route get to 198.51.100.1 from 192.168.0.2 iif eth0

This should give a response of the form:

198.51.100.1 from 192.168.0.2 via 203.0.113.2 dev eth1  src 192.168.0.1
    cache <src-direct>  mtu 1500 advmss 1460 hoplimit 64 iif eth0

The main points to verify are that the IP address of the next hop is correct (203.0.113.2 in this case) and that the packet is being sent onwards through the appropriate interface (eth1).

Similarly, check how inbound packets are routed with the command:

ip route get to 192.168.0.2 from 198.51.100.1 iif eth1

which should give a response of the form:

192.168.0.2 from 198.51.100.1 dev eth0  src 203.0.113.1
    cache  mtu 1500 advmss 1460 hoplimit 64 iif eth1

For more guidance about troubleshooting the routing table see Troubleshooting the routing table.

Check firewalling

The correct place to perform packet filtering of routed traffic would be in the FORWARD chain of the filter table:

iptables -t filter -L FORWARD -n

but packets could also go missing in the nat or mangle tables so it is worth checking them too:

iptables -t nat -L -n
iptables -t mangle -L -n

You can obtain more detailed visibility of how packets are traversing iptables by inspecting the packet counter associated with each rule.

First zero the counters:

iptables -t filter -Z FORWARD

then perform the ping test and inspect the counter:

iptables -t filter -L FORWARD -nv

If you had explicitly blocked traffic from the machine you were attempting to ping then you might see output similar to:

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination
    6   504 DROP       all  --  any    any     198.51.100.1         anywhere

This shows that 6 packets were dropped by the first (and only) rule in this chain. No packets reached the end of the chain.

The counts may become difficult to interpret if the router is carrying more than just your test traffic. In that case it may be necessary add extra rules (or chains) purely for the purpose of gathering statistics.

Errors

Cannot find /proc/version

An error from sysctl of the form:

Cannot find /proc/version - is /proc mounted?

probably indicates, as it suggests, that /proc has not been mounted. The simplest way to check is to list the content of that directory. See Mounting /proc for further guidance.