Convert Linux into NAT Router
Sometimes it comes in handy to have a Linux box act as a router. You might not have a switch lying around. You might want to monitor all traffic coming and going to some device. In this post, we will set up Linux to act as a simple IPv4 NAT router.
We will call the Linux machine linux
and the machine using the Linux box for
internet breakout remote
.
-
You need 2 NICs on your Linux. They can be 2 ethernet ports. But you could also use your wireless interface for this. In this post, we assume they are cabled connections called
eth0
andeth1
. -
Connect
eth0
to the gateway. -
Connect the two machines with an ethernet cable. The cable in the Linux machine should go in
eth1
. -
Make sure the interfaces on both sides are up:
linux# ip link set eth1 up remote# ip link set eth0 up
Reminder: you can abbreviate these commands to
ip l s eth<n> up
. -
Assign both ends an RFC 1918 private IPv4 address. You could use link-local addresses (APIPA):
linux# ip addr add 169.254.0.1/32 peer 169.254.0.2 dev eth1 remote# ip addr add 169.254.0.2/32 peer 169.254.0.1 dev eth0
Shorter:
ip a a 169.254.0.1/32 peer 169.254.0.2 dev eth1
I configure the addresses to be point-to-point, because there are only 2 hosts on this network and they are directly connected.
-
Enable IPv4 forwarding in the kernel on the Linux router
linux# sysctl -w net.ipv4.ip_forward=1
-
Enable NAT on the Linux router.
linux# iptables -t nat -A POSTROUTING \ -s 169.254.0.0/16 \ -o eth0 \ -j MASQUERADE
This will rewrite the source address of the packets with the original source address in the
169.254/16
network to the primary source address of the outgoing interfaceeth0
. TheMASQUERADE
target is easiest to use, but:It should only be used with dynamically assigned IP (dialup) connections: if you have a static IP address, you should use the
SNAT
target. Masquerading is equivalent to specifying a mapping to the IP address of the interface the packet is going out, but also has the effect that connections are forgotten when the interface goes down. This is the correct behavior when the next dialup is unlikely to have the same interface address (and hence any established connections are lost anyway).The alternative is to use the
SNAT
target with a static (private) IPv4 address. It should be an address configured on the interface which you either configured statically yourself, or you got from a DHCP server. You can check withip -br addr show eth0
. Here, I am using192.168.1.123
:linux# iptables -t nat -A POSTROUTING \ -s 169.254.0.0/16 \ -o eth0 \ -j SNAT --to-source 192.168.1.123
-
If you have a strict firewall on your Linux router, you might have set
iptables -P FORWARD DROP
. You need to allow traffic to flow between the 2 NICs. For example:linux# iptables -I FORWARD -i eth1 -o eth0 -j ACCEPT linux# iptables -I FORWARD -i eth0 -o eth1 -j ACCEPT
-
Finally, make the Linux router the default gateway of the dependent box:
remote# ip route add default via 169.254.0.1 dev eth0
You can abbreviate
route add
tor a
.
A Note on Interface Names
If you have complicated setup with virtual interfaces (VPN, VLAN) and a firewall
in place, add logging to your firewall rules when packets get dropped, so you
know which interfaces to use in your source NAT (-t nat -A POSTROUTING
) and
FORWARD
rules.