In this guide we will show you a simple way to change the destination of output IP traffic destination from A to B using iptables NAT rules in Linux.
There are many scenarios where these rules can be very useful. Some that spring to mind are:
There are many more examples where this might come in handy, those are just a few.
Most people are used to simply running iptables -L to show all rules inside of iptables, however NAT rules are excluded from these results as they are not classed as "filter" rules.
To show NAT rules we need to run the following:
iptables -t nat -nvL
You should get an output similar to the following:
[root@server ~]# iptables -t nat -nvL
# Warning: iptables-legacy tables present, use iptables-legacy to see them
Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
In the example above we have no NAT rules present inside of iptables.
The basic structure for a NAT rule to change the destination IP for output packets is the following:
iptables -t nat -A output -p <TCP/UDP> -d <DESTINATION_IP> -j DNAT --to-destination <NEW_DESTINATION_IP>
For a more real-world example if we had the following hosts:
I want to redirect TCP traffic going to A to B then the NAT rule to add would be:
iptables -t nat -A output -p tcp -d 192.168.0.1 -j DNAT --to-destination 192.168.0.7
We can bump up the complexity of the rule by adding further port conditions inside of it. The basic structure to include ports in the NAT rule would be:
iptables -t nat -A output -p <TCP/UDP> -d <DESTINATION_IP> --dport <DESTINATION_PORT> -j DNAT --to-destination <NEW_DESTINATION_IP>:<NEW_DESTINATION_PORT>
To demonstrate this, take a scenario where we have the following hosts:
I want to redirect just the SSH traffic going towards B to C from A, so in effect when I SSH to B from A I am actually SSH to C. In this scenario we could add this rule on A:
iptables -t nat -A output -p tcp -d 192.168.0.5 --dport 22 -j DNAT --to-destination 192.168.0.7:22
Above rule will redirect SSH traffic from A going to B to C instead.
Remember you can view your rules after you have created them by running:
iptables -t nat -nvL
Running iptables -F will not clear NAT rules inside of iptables, the -F flag only clears filter rules. To clear any NAT based rules we have to run:
iptables -t nat -F
More useful iptables tips and tricks can be found in the user manual located here.