I have a Raspberry Pi 4 which I solely use to block ads using Pi-hole. I recently came across a situation where I needed to create a separate network for my home lab which also requires Internet connectivity. There are many ways to accomplish this task but for me using the Pi as a router seemed to be the most straightforward way.
Diagram
pi@raspberrypi:~ $ ip ad
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
link/ether dc:a6:32:04:d2:56 brd ff:ff:ff:ff:ff:ff
inet 10.10.0.1/24 brd 10.10.255.255 scope global noprefixroute eth0
valid_lft forever preferred_lft forever
inet6 fe80::a7c0:e802:57e3:90a6/64 scope link
valid_lft forever preferred_lft forever
3: wlan0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether dc:a6:32:04:d2:57 brd ff:ff:ff:ff:ff:ff
inet 192.168.0.10/24 brd 192.168.0.255 scope global noprefixroute wlan0
valid_lft forever preferred_lft forever
inet6 fe80::981a:3238:f19:c228/64 scope link
valid_lft forever preferred_lft forever
As you can see above:
- Pi is connected to the ISP provided router via Wi-Fi (wlan0, and gets internet)
- Pi's Wi-Fi IP address is 192.168.0.10/24 and the gateway is 192.168.0.1
- I connected my home lab directly to Pi's ethernet port (eth0) and assigned an IP of 10.10.0.1/24
- Home lab devices get an IP address in the 10.10.0.0/24 subnet and use 10.10.0.1 as the gateway (Pi is the gateway for the lab devices)
My ultimate goal is to provide Internet connectivity to the devices in the home lab. There are two important things you need to be familiar with, IP routing and NAT.
When the traffic from my lab devices arrives at the Pi's eth0 interface, we want the traffic to be routed to the wlan0 interface and then to the Internet. Let's say the traffic that arrives on the eth0 interface has the source IP of 10.10.0.10 and the destination IP of 8.8.8.8. What we want it to happen is to change the source IP from 10.10.10.10 to the IP address of the wlan0 interface which is 192.168.0.10. This is achieved by Network Address Translation (NAT) On Linux, NAT can be configured using iptables.
IPtables
Most Linux distros come with a powerful firewall built-in, commonly referred to as iptables. Iptables places rules into predefined chains (INPUT, OUTPUT and FORWARD) that are checked against any network traffic relevant to those chains and a decision is made about what to do with each packet based upon the outcome of those rules.
The first thing we need to do is turn on routing on the Pi which is disabled by default. Routing can be enabled by editing the sysctl.conf file. The line we want is already there, we just want to uncomment it out.
# Uncomment the next line to enable packet forwarding for IPv4
net.ipv4.ip_forward=1
In the context of this example:
- INPUT - All packets destined for the Pi
- OUTPUT - All packets originating from the Pi
- FORWARD - All packets neither destined for nor originating from the Pi, but passing through (routed by) the Pi. This is the chain we are interested in most.
The end state that we want is that packets arriving at Pi's eth0 interface from the home lab devices have to be modified such that the source address is equal to Pi's wlan0 address as shown below.
The command to configure that is:
iptables -t nat -A POSTROUTING -o wlan0 -j MASQUERADE
Let's go through each parameter one-by-one.
- iptables - The command-line utility for configuring the rules
- -t nat - Configuration of NAT rules.
- -A POSTROUTING - Append (-A) a rule to the POSTROUTING chain
- -o wlan0 - The rules apply for packets that leave the Wi-Fi interface (-o stands for 'output')
- -j MASQUERADE - The action that should take place is to 'masquerade' (NATing) the packets.
We need two more commands which are required to accept the traffic from eth0 interface and allow established connections from the wlan0 interface to eth0 interface (Return traffic from the Internet)
iptables -A FORWARD -i eth0 -o wlan0 -j ACCEPT
iptables -A FORWARD -i wlan0 -o eth0 -m state --state RELATED,ESTABLISHED -j ACCEPT
That's all, the routing and NAT should be working and the devices on my home lab should be able to route via the Pi and go out to the Internet.
One more thing
By default, these configuration changes are not persistent, so when you reboot next time the configurations will be wiped out. To make them persistent, you need to install a utility called iptables-persistent.
pi@raspberrypi:~ $ sudo apt-get install iptables-persistent
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following packages were automatically installed and are no longer required:
[......]
Setting up iptables-persistent (1.0.11+deb10u1) ...
Processing triggers for man-db (2.8.5-2) ...
Processing triggers for systemd (241-7~deb10u4+rpi1) ...
During the installation, you will get a prompt to make the changes persistent, just select yes and you are good to go.
Closing up
I've been using Pi as a router for a couple of years now without any issues. Feel free to let me know in the comments if you have any issues or questions.