[fw3, iptables] How is the DNAT ctstate used and why do we ACCEPT such packets


I recently noticed that fw3 in OpenWrt inserts these iptables rules [*]:

root@OpenWrt:~# iptables -S  | grep DNAT
-A zone_lan_forward -m conntrack --ctstate DNAT -m comment --comment "!fw3: Accept port forwards" -j ACCEPT
-A zone_lan_input -m conntrack --ctstate DNAT -m comment --comment "!fw3: Accept port redirections" -j ACCEPT
-A zone_wan_forward -m conntrack --ctstate DNAT -m comment --comment "!fw3: Accept port forwards" -j ACCEPT
-A zone_wan_input -m conntrack --ctstate DNAT -m comment --comment "!fw3: Accept port redirections" -j ACCEPT

While I can see an explanation of the DNAT conntrack state in iptables-extensions(8), namely,

       DNAT   A  virtual  state,  matching if the original destination differs
              from the reply source.

I don't understand why such packets need to be ACCEPT'ed and what would break if they aren't? Does anyone know a reason for the above rules? Or at least where can I read more about this?

By the way, I'm running OpenWrt 21.02.3 r16554-1d4dea6d4f.

[*] Although I noticed this recently, the corresponding commit in fw3 appeared in 2013:

commit d54cb962ebafdf2fde7256e234a2f3cfe8223c71
Author: Jo-Philipp Wich <jow@openwrt.org>
Date:   Wed Nov 6 23:56:36 2013 +0000

    Use a global -m conntrack --ctstate DNAT rule to accept all port forwards of
 a given zone in filter

Thanks in advance!

You can find the explanation in the comments.

If such a rule is missing from the FORWARD chain, all port forwards will be blocked by the default forwarding policy, which in most cases is DROP or REJECT.
You will need to create permissive rules in the corresponding FORWARD chain, accepting connections from specific IP addresses or open the FORWARD chain entirely, which is not recommended.

This will allow redirects to the router itself even if there is a rule (or policy) in the INPUT chain, blocking direct access to the specified port(s).
This is a very rare situation and I presume the rules are created "just in case".


Thanks for the explanation!

I suspected what you said about the FORWARD chain, but I'm still confused about INPUT? Doesn't ACCEPTing the DNAT state allow bypassing an otherwise closed firewall, especially on the WAN interface?

Also, I understand that for port forwarding you need to add appropriate rules in FORWARD and nat/PREROUTING. But again, if I don't have port forwarding configured in nat, wouldn't the DNAT rule lead to a "leakage" of packets to/from LAN (at least).

In other words, it seems that effects of these DNAT rules are not bening, so I wonder is there a way to override it other than adding a blocking rule in /etc/firewall.user?

When you do REDIRECT

Sure, but you have 2 options:

  1. You make the DNAT and the accept dnat state does the rest
  2. You make the DNAT and then allow on the firewall the forward from the internet to the internal host.

If you don't have DNAT (port forward), how would the DNAT rule lead to a leakage? Do you realize that it doesn't make sense?

I am not sure what you classify as not benign, nor if you fully grasp what this rules do.
So let's go back. wan->lan forwarding is dropped. A packet comes from wan and matches a rule for port forward. Destination IP is rewritten and leaves the PREROUTING chain of the NAT table to enter the FORWARDING (or INPUT) chain of the filter table. If a packet is in conntrack with the state of DNAT, meaning there is a rule to port forward this type of packets, then we ACCEPT the forwarding regardless of the fact that generally wan->lan is not accepted. I hope it is clear now.


Oh... right. Forgot about that.

Hmm... it does not indeed -- that was my brain freeze (or lack of coffee). So, basically, --ctstate DNAT is never matched, unless there is a DNAT rule in nat/PREROUTING?

Yes, you are right -- I was confused about these rules. Thanks for clearing that up!

Basically, yes!

Thanks :slight_smile:

1 Like

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.