Does iptables implicitly and automatically add the reverse/inverse rules for every NAT rule that is added explicitly?
Typically, assuming a DROP policy, for each INPUT rule in the filter table there is a corresponding OUTPUT rule which accepts related or established traffic (and vice versa). For example, to enable inbound SSH to pass through an iptables firewall there would be an INPUT rule to allow incoming connections to be established:
iptables -A INPUT -i eth0 -p tcp --dport 22 -m state --state NEW,ESTABLISHED -j ACCEPT
But there would also be a corresponding OUTPUT rule allowing return traffic:
iptables -A OUTPUT -o eth0 -p tcp --sport 22 -m state --state ESTABLISHED -j ACCEPT
While this kind of explicit reverse-traffic rule is necessary in the filter table, it seems that this is not the case for the NAT table.
Consider the following excerpts from various unofficial references:
Certain events will cause a table's chain to be skipped during processing. For instance, only the first packet in a connection will be evaluated against the NAT rules. Any nat decisions made for the first packet will be applied to all subsequent packets in the connection without additional evaluation. Responses to NAT'ed connections will automatically have the reverse NAT rules applied to route correctly.
But netfilter (i.e., the packet filtering/mangling framework that's the 'engine' of iptables) is smart enough. Whenever an incoming [NAT] packet is received, it's matched with netfilter's conntrack table. If the packet is a reply to an existing outgoing connection (ACK flag set, matching IP:port, matching TCP sequence number, etc), netfilter automatically performs DNAT. No need for additional rules.
Fortunately the netfilter framework automatically adds to each rule its inverse rule, therefore we only have to set one explicit rule. Usually the decision for one of these two rules is made by taking the one with the lower level of undetermination. For example, the rule 'Replace the sender's address for all packets from the local subnet' is much easier than 'if a client has sent something to a server, then replace the receipient in the server's response by something'. As a rule of thumb can be used that the rule that is executed first is the one that is set explicitly in the kernel.
I've perused the official netfilter documentation but I haven't managed to find this behavior mentioned anywhere. Is there an official reference that corroborates the preceding claims?
sudo conntrack -L
(package conntrack-tools).