Iptables – Is the NAT Table INPUT Chain Necessary?

firewalliptables

The iptables man page suggests the following standard tables and chains:

                raw     mangle  nat     filter
PREROUTING       X       X       X       
INPUT                    X       X       X
FORWARD                  X               X
OUTPUT           X       X       X       X
POSTROUTING              X       X

But the diagram in the iptables Wikipedia page does not indicate the nat INPUT chain is used. I know the diagram is a simplification, simply because they for instance intentionally omit the security table. This might be a pedantic question as I try to teach myself firewalls, but the answer could be interesting.
enter image description here

Best Answer

UPDATE: fix nat/INPUT order.

The schematic didn't include nat/INPUT initially, but I incorrectly wrote that int was before filter/INPUT, and this schematic got (incorrectly) updated later with this chain between mangle/INPUT and filter/INPUT which turns out to be wrong.

nat/INPUT hooks after filter/INPUT.

As the nat type is special and is linked with conntrack, it also turns out that nftables's priority doesn't even depend on the hook priority which for nat affects only priorities between multiple chains within the same nat hook. Using nftables instead of iptables can't alter this by changing the priority to a value lower than filter/INPUT's 0 or mangle/INPUT's -150: it always hooks at exactly 100. (Same behavior with nat/PREROUTING: it always hooks at exactly -100 for PREROUTING even if giving a chain priority of -199). All this can be tested using iptables' -j TRACE or nftables' meta nftrace set 1 features and looking at the resulting order of traversed chains. Tests made on kernel 5.13.x, specific behavior about this might change in the future. iptables not even being able to change these priorities doesn't have a choice anywhere anyway.

As @Andrew Bate wrote, the correct schematic giving the correct order can be found there with currently this:

schematic

that said, about the question...


nat/PREROUTING will apply before the initial routing decision, for all cases (routed, or for local endpoint traffic), nat/INPUT will happen after the initial routing decision, only if traffic is deemed local.

The way it's implemented in relation to routing and connection tracking, before routing, with nat/PREROUTING, you're allowed to change what will affect routing: the destination (-j DNAT), but not the origin. After routing, with nat/INPUT, that's the opposite: you can't change the destination, but you can change the origin (-j SNAT).

You have a certain inverted symmetry with nat/OUTPUT (which is on the schematic) and nat/POSTROUTING: nat/OUTPUT is only for locally initiated traffic and can alter routing decision, like in nat/PREROUTING, thus can alter destination (with -j DNAT), second is for all traffic, routed or locally initiated, after any routing decision was already done (and can change source like nat/INPUT with -j SNAT).

To answer the question, nat/INPUT didn't exist until it was needed. It was specifically created to handle new emerging cases avoiding requiring namespaces but using conntrack zones instead. It appeared in 2010. This link includes usage examples having motivated its creation, but it's quite difficult to grasp since it uses conntrack zones (which allow to separate totally identical flows (same 5-tuple protocol,saddr,sport,daddr,dport) into different conntrack entries by adding a zone tag on them. For example for special policy routed traffics, one arriving from eth0 going to eth2, the other arriving from eth1 going to eth3, or as in the first link to loop back traffic and track/nat it separately).