In this second part, we’ll discuss how to set up a NAT in Linux, using iptables. As in the previous blog, here are the stats of my VM’s:
The first thing that we’ll need to do is allow the computer to forward traffic between interfaces.
[root@server1 ~]# sysctl -a | grep net.ipv4| grep forward
net.ipv4.conf.all.forwarding = 0
net.ipv4.conf.all.mc_forwarding = 0
net.ipv4.conf.default.forwarding = 0
net.ipv4.conf.default.mc_forwarding = 0
net.ipv4.conf.lo.forwarding = 0
net.ipv4.conf.lo.mc_forwarding = 0
net.ipv4.conf.eth0.forwarding = 0
net.ipv4.conf.eth0.mc_forwarding = 0
net.ipv4.conf.eth1.forwarding = 0
net.ipv4.conf.eth1.mc_forwarding = 0
net.ipv4.ip_forward = 0
[root@server1 ~]# sysctl net.ipv4.ip_forward=1
net.ipv4.ip_forward = 1
[root@server1 ~]# vim /etc/sysctl.conf
[root@server1 ~]# grep net.ipv4.ip_forward /etc/sysctl.conf
net.ipv4.ip_forward = 1
Editing the /etc/sysctl.conf makes the setting persistent across reboots.
Since we made changes to iptables in the previous blog, I’ll again give myself a clean slate to work with.
[root@server1 ~]# iptables -F
[root@server1 ~]# iptables -F -t nat
[root@server1 ~]# iptables -L
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain FORWARD (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
[root@server1 ~]# iptables -L -t nat
Chain PREROUTING (policy ACCEPT)
target prot opt source destination
Chain POSTROUTING (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
I’ll verify that my client computers can ping the gateway, each other, but can not get to the internet.
[root@client1 ~]# for i in 192.168.101.1 \
192.168.101.102 \
4.2.2.2; \
do ping -c 1 $i; done
PING 192.168.101.1 (192.168.101.1) 56(84) bytes of data.
64 bytes from 192.168.101.1: icmp_seq=1 ttl=64 time=0.543 ms
--- 192.168.101.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.543/0.543/0.543/0.000 ms
PING 192.168.101.102 (192.168.101.102) 56(84) bytes of data.
64 bytes from 192.168.101.102: icmp_seq=1 ttl=64 time=0.412 ms
--- 192.168.101.102 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.412/0.412/0.412/0.000 ms
PING 4.2.2.2 (4.2.2.2) 56(84) bytes of data.
--- 4.2.2.2 ping statistics ---
1 packets transmitted, 0 received, 100% packet loss, time 10000ms
[root@client2 ~]# for i in 192.168.101.1 \
192.168.101.101 \
4.2.2.2; \
do ping -c 1 $i; done
PING 192.168.101.1 (192.168.101.1) 56(84) bytes of data.
64 bytes from 192.168.101.1: icmp_seq=1 ttl=64 time=0.402 ms
--- 192.168.101.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.402/0.402/0.402/0.000 ms
PING 192.168.101.101 (192.168.101.101) 56(84) bytes of data.
64 bytes from 192.168.101.101: icmp_seq=1 ttl=64 time=0.224 ms
--- 192.168.101.101 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.224/0.224/0.224/0.000 ms
PING 4.2.2.2 (4.2.2.2) 56(84) bytes of data.
--- 4.2.2.2 ping statistics ---
1 packets transmitted, 0 received, 100% packet loss, time 10000ms
Now, I’ll implement the NAT.
[root@server1 ~]# iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
[root@server1 ~]# iptables -L
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain FORWARD (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
[root@server1 ~]# iptables -L -t nat
Chain PREROUTING (policy ACCEPT)
target prot opt source destination
Chain POSTROUTING (policy ACCEPT)
target prot opt source destination
MASQUERADE all -- anywhere anywhere
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
Now my client PC’s can get out to the Internet:
[root@client1 ~]# ping -c 2 4.2.2.2
PING 4.2.2.2 (4.2.2.2) 56(84) bytes of data.
64 bytes from 4.2.2.2: icmp_seq=1 ttl=56 time=10.2 ms
64 bytes from 4.2.2.2: icmp_seq=2 ttl=56 time=9.96 ms
--- 4.2.2.2 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1011ms
rtt min/avg/max/mdev = 9.960/10.103/10.246/0.143 ms
[root@client2 ~]# ping -c 2 4.2.2.2
PING 4.2.2.2 (4.2.2.2) 56(84) bytes of data.
64 bytes from 4.2.2.2: icmp_seq=1 ttl=56 time=10.3 ms
64 bytes from 4.2.2.2: icmp_seq=2 ttl=56 time=9.98 ms
--- 4.2.2.2 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1011ms
rtt min/avg/max/mdev = 9.986/10.144/10.303/0.187 ms
This only works with the single line:
iptables -t nat -I POSTROUTING -o eth0 -j MASQUERADE
because the default rule for the INPUT and FORWARD chains are to ACCEPT the traffic:
[root@client2 ~]# iptables -L
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain FORWARD (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
[root@client2 ~]# iptables -L -t nat
Chain PREROUTING (policy ACCEPT)
target prot opt source destination
Chain POSTROUTING (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
Otherwise, you would need a couple extra rules to allow the traffic.
Those rules would be:
iptables -t nat -I POSTROUTING -o eth0 -j MASQUERADE
iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A FORWARD -i eth1 -o eth0 -j ACCEPT