trying to figure out my mistake in the following very simple scenario:

|peerA|(Aip:Aport) <--> (Bdev:Bip:Bport)|NatNode|(Cdev:Cip:Cport) <--> (Dip:Dport)| peerD

(peer A emits datagrams to Bip:Bport, the NatNode translates them as sent by Cip:Cport, and destined to Dip:Dport; and viceversa )

what I did, with empty iptables and "vanilla" routing table, is:

iptables -p udp -t nat -A PREROUTING -s Aip -d Bip -i Bdev --destination-port Bport -j DNAT --to-destination Dip:Dport

iptables -p udp -t nat -A POSTROUTING -s Aip -d Dip -o Cdev --destination-port Dport -j DNAT --to-source Cip:Cport

(plus the rules for the reverse direction, and one LOG target for each -t nat and -t filter main targets)

what I expected was: - correct rewriting (and is OK, as shown by wireshark) - each incoming packet enters from PREROUTING (routing decision, possibly to Cdev) traverse FORWARD once (routing decision, possibly to Cdev), then POSTROUTING once, then it goes to the network.

what I got is (examining the logging): 1. the first packet traverse PREROUTING once, filter/FORWARD a ton of times (yep, same packet id), then POSTROUTING a lot of times, then is emitted to the network once and the remote peers receives it. 2. from the second datagram onwards, everything seems to happen but the translated datagram is not emitted on the device. 3. if I wait enough (say >15 secs) and retry, again, the head datagram of the new sequence behaves like 1., from the second onwards like 2.

Also tried to remove the -i and -o options but seems to not change anything.

What I'm doing wrong here?

I cannot spot the issue, it seems to me that I did "as intended", instinctively I suspect that something is going wrong in the routing decision points, and maybe the packets like in 2. are not emitted by some safeguard behaviour of the linux tcp/ip stack...

I'm pretty sure it's my own fault but cannot find where.

thank you for your help!

  • duplicates here probably means wrong routing (reminder: iptables doesn't route). I bet those packets would show decreasing TTL values in the IP header. So routes would have needed to be provided
    – A.B
    Oct 21, 2020 at 9:20

1 Answer 1


If you want to make classic NAT for Dip and implement port forwarding for it's Dport, then you don't need any specially crafted POSTROUTING rules for it, just add generic -j MASQUERADE.

And.. DNAT in POSTROUTING? Did you make a typo?

I usually implement classic NAT as (assuming blocking firewall is set up, and conntrack takes back all the "answered" packets):

iptables -I POSTROUTING -o ppp0 -j MASQUERADE

iptables -I FORWARD -i eth0 -o ppp0 -j ACCEPT

iptables -I PREROUTING -i ppp0 -p tcp --dport 80 -j DNAT --to local_ip:80

Here, eth0 is local iface in same subnet as local_ip, ppp0 is internet iface.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .