Octet

How do you turn a Linux box into a router, and why is enabling ip_forward often not enough?

Show the answer

Say this first

By default Linux behaves as a host and drops packets that are not addressed to it. net.ipv4.ip_forward=1 lets it route IPv4 between interfaces; IPv6 has its own switch, net.ipv6.conf.all.forwarding=1. sysctl -w changes the running value; a file in /etc/sysctl.d/ makes it survive a reboot. After that the packets still have to pass the firewall FORWARD chain and rp_filter, and the far side needs a route back.

Go deeper

Check and set

Output
$ sysctl net.ipv4.ip_forward
net.ipv4.ip_forward = 0
$ sudo sysctl -w net.ipv4.ip_forward=1
net.ipv4.ip_forward = 1
Shell
echo 'net.ipv4.ip_forward = 1' | sudo tee /etc/sysctl.d/90-router.conf
sudo sysctl --system      # reload every sysctl file
cat /proc/sys/net/ipv4/ip_forward

The checklist after forwarding is on

  1. Firewall FORWARD chain. Docker sets the filter FORWARD policy to DROP when it starts; hardened images often do the same. iptables -S FORWARD or nft list ruleset.
  2. rp_filter. With strict mode, packets that arrive on an interface the router would not use to reach their source are dropped silently.
  3. Return route. The next router or the server must know the way back to the source subnet, or you need NAT.
  4. NAT if the inside uses private addresses and the outside does not route them.

Who turns it on for you

Docker, libvirt and Kubernetes components set ip_forward=1 when they start, which is why a host can suddenly start routing after someone installs a container runtime.

Traps

  • Using sysctl -w and forgetting to persist it. The router stops routing after the next reboot.
  • Assuming forwarding is the whole job. The FORWARD chain policy is the next most common reason.
How did you do?Book 3.3 Internet (IP)