RHCE Series: Use iptables to implement packet filtering and configure network address translation (NAT): Part 2

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.
[[email protected] ~]# 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
[[email protected] ~]# sysctl net.ipv4.ip_forward=1
net.ipv4.ip_forward = 1
[[email protected] ~]# vim /etc/sysctl.conf
[[email protected] ~]# 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.
[[email protected] ~]# iptables -F
[[email protected] ~]# iptables -F -t nat
[[email protected] ~]# 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
[[email protected] ~]# 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.


[[email protected] ~]# 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

[[email protected] ~]# 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.


[[email protected] ~]# iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
[[email protected] ~]# 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
[[email protected] ~]# 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:


[[email protected] ~]# 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

[[email protected] ~]# 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:


[[email protected] ~]# 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
[[email protected] ~]# 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