Port forward with iptables

5,981

Solution 1

When you are trying to reach localhost, your source address is 127.0.0.1, as is your destination address. So, packet looks something like this:

 | SRC        |  DST       |
 | 127.0.0.1  |  127.0.0.1 |

Since packets that are locally generated first traverse OUTPUT chain, you modify the packet with DNAT rule:

iptables -t nat -A OUTPUT \
         -d 127.0.0.1 \
         -p tcp --dport 80 \
         -j DNAT \
         --to 172.17.42.1:80

After OUTPUT chain, packet looks like this:

 | SRC        |  DST        |
 | 127.0.0.1  |  172.17.42.1 |

So, the first error you see is that even if this packet gets routed outside the source device, destination will not know how to correctly return it. Thus, you also need to add additional SNAT rule:

iptables -t nat -A POSTROUTING \
         -d 172.17.42.1 \
         -p tcp --dport 80 \
         -j SNAT \
         --to-source <your_ip_addr>

Now, packet will look pretty much correct to exit on the network (source address will be the public address of this device and not localhost address).

But, this won't solve your pain just yet.

Routing decisions for packets generated on a local machine are taken in two places.

  • before the OUTPUT chain
  • after the OUTPUT chain and before POSTROUTING

Decision for this packet will be made in the second stage, before the source IP is rewritten in POSTROUTING chain...

So, kernel security mechanism will drop the packet because by default kernel refuses to route packets with src of 127.0.0.1. That means that even mangle coupled with fwmark wouldn't help us here. What's needed for this to work is to enable route_localnet. That's the per-iface variable that enables the use of 127/8 for local routing purposes (default is 0 - aka disabled).

sysctl -w net.ipv4.conf.all.route_localnet=1

You can safely change 'all' for the name of the outgoing interface in your case.

Now, packets will get routed by the previous rules in the table, and since we had the POSTROUTING SNAT, we will fix the source ip of 127.0.0.1 and rewrite it.

Hope this helps.

PS. sorry before 2-3 edits, it's 5AM here and I'm still awake :)

Solution 2

Before one jumps straight into firewall rules, one should also perform a simple forwarding check. Rather like when one checks the power cord is plugged in before taking apart the hardware.

Run:

cat /proc/sys/net/ipv4/ip_forward

If you get a zero, IPv4 will not forward. You'll need to turn this on.

To turn it on immediately and ephemerally to verify behavior:

echo 1 > /proc/sys/net/ipv4/ip_forward

The above turns it on for the machine but is simply modifying a kernel setting on the fly and will not be "saved".

Edit the sysctl.conf file to make the proper permanent change and ensure the following setting:

net.ipv4.ip_forward = 1
Share:
5,981

Related videos on Youtube

svobol13
Author by

svobol13

Updated on September 18, 2022

Comments

  • svobol13
    svobol13 almost 2 years

    I got lo (127.0.0.1) and eth0 (172.17.0.8). I want to redirect packets that land on 127.0.0.1:80 to 172.17.42.1:80 (route from eth0).

    I tried

    iptables -t nat -A OUTPUT -p tcp --dport 80 -d 127.0.0.1 -j DNAT --to 172.17.42.1:80
    

    But when I do curl localhost:80 I get no response, when I do curl 172.17.42.1:80 it just works.

    • Clément Perroud
      Clément Perroud over 9 years
      No, because packets that are generated locally don't go through a PREROUTING at all. First routing decision is taken before the packet enters OUTPUT chain, and second (final) routing decision is taken after the packet exits OUTPUT and before it enters POSTROUTING chain.
    • Magellan
      Magellan over 9 years
      You turned on ipv4 forwarding in your sysctl.conf (and then reloaded) or in the appropriate location in /proc, yes?
  • Clément Perroud
    Clément Perroud over 9 years
    ACtually you don't need ip_forward for locally generated packets. ip_forward only allows incoming packets to be forwarded to other machines, it doesn't do anything for packets originating from localhost.
  • rjh
    rjh about 7 years
    This is fantastic thanks. I really appreciated how you explained each part of the routing and why it won't work without an extra step.