Feed on
Posts
Comments

IPtables and NAT

By default, a linux machine will drop traffic that’s not destined for an IP bound locally. If you’re planning on receiving traffic not ultimately destined for you (ie: you’re behaving as a router along the path to the ultimate destination), then you’ll need to flip a couple flags in /etc/sysctl.conf to allow traffic forwarding:

net.ipv4.ip_forward = 1
net.ipv4.conf.default.rp_filter = 1

Reload sysctl:

sysctl -p

 

Add your NAT rule to the iptables prerouting chain in the nat table. For example, maybe you’re plugged into both a public and private network, and you want to forward traffic to your public IP on tcp/80 to the web server on your private network. Note that this particular step is only necessary if the public network needs to be able to reach the webserver on our private network. You can skip the PREROUTING chain altogether if you only want to allow egress traffic from the servers on your private network, and block all ingress.

[email protected][~]# iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to-destination 10.0.0.12:80
[email protected][~]#

 

When the webserver on 10.0.0.12 tries to respond to the public address, that’s going to be problematic. Since the client originally connected to us and not the webserver, we can’t have the webserver being visible in the response – this would cause a TCP RESET. The return traffic will definitely hit us though, ’cause we’re that webserver’s default gateway. As such, we can correct this by masquerading as the source of this routed traffic.

[email protected][~]# iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
[email protected][~]#

 

Make sure we allow the relevant traffic as well. Since we’re routing port 80 to the webserver, we’ll want port 80 open on the INPUT chain. Since the webserver sends all its traffic through us, we need to allow all of it out via our FORWARD chain – unless we’re doing egress filtering here, in which case you’d glorify your FORWARD chain.

[email protected][~]# iptables -A FORWARD -j ACCEPT
[email protected][~]# iptables -A INPUT -p tcp --dport 80 -j ACCEPT
[email protected][~]#

 

Oh and one more thing. If you want to NAT traffic that’s originating from this router server in the first place, then you need to add your rules to the OUTPUT chain in the nat table. For example, say we’ve setup a SOCKS proxy on port 8080 and we want to force all our outgoing HTTP traffic to use that SOCKS proxy. Here’s how you’d do that:

[email protected][~]# iptables -t nat -A OUTPUT -p tcp --dport 80 -j DNAT --to-destination 127.0.0.1:8080
[email protected][~]#

This can be really useful in cases where an application is trying to connect to a remote resource, but that resource has changed IPs and it’s going to take you 3 weeks to correct every single instance of the old IP within your code. Instead of being offline for those three weeks, throw up a NAT rule so attempts to reach the old IP are NAT’d to the new IP instead:

[email protected][~]# iptables -t nat -A OUTPUT -d 10.0.0.50 -j DNAT --to-destination 192.168.0.50
[email protected][~]#

 

You won’t see your iptables NAT rules in the default table. You need to specify “-t nat” to see these rules:

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

[email protected][~]# iptables -nL -t nat
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination
DNAT       tcp  --  0.0.0.0/0            0.0.0.0/0           tcp dpt:80 to:10.0.0.12:80

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination
MASQUERADE  all  --  0.0.0.0/0           0.0.0.0/0

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination
[email protected][~]#

 

Oh, and just in case we’re not that backend server’s default gateway, make it so:

route add default gw 10.0.0.1

Leave a Reply