II have a terrible time keeping this straight. This is a memory aid. I think it is correct, but it has been assembled from internet sources and not from reading the code, so this is not authoritative.
- Incoming packets:
NF_IP_PRE_ROUTING HOOK (PREROUTING CHAIN)
- raw table [PREROUTING]
- contrack
- mangle table [PREROUTING]
- nat table [PREROUTING] (dnat)
- route decision (either for us, or another host)
- IF Destined for this host:
NF_IP_LOCAL_IN HOOK (INPUT CHAIN)
- mangle table [INPUT]
- filter table {INPUT]
- security table [INPUT]
- nat table [INPUT (rarely used)] (snat)
- IF Destined for another host:
NF_IP_FORWARD HOOK (FORWARD CHAIN)
- mangle table [FORWARD]
- filter table [FORWARD]
- security table [FORWARD]
- (-> do output postrouting)
- Packets generated on local host:
NF_IP_LOCAL_OUT HOOK (OUTPUT CHAIN)
- route decision (select interface, etc)
- raw table [OUTPUT]
- contrack
- mangle table [OUTPUT (rarely used)]
- nat table [OUTPUT (rarely used)] (dnat)
- route decision
- filter table [OUTPUT]
- security table [OUTPUT}
(-> do output postrouting)
- Output PostRouting
NF_IP_POST_ROUTING HOOK (POSTROUTING CHAIN)
- mangle table [POSTROUTING]
- nat table [POSTROUTING] (snat/masquerade)
contrack means connection tracking, unless the (always preceeding) raw table says not to track.
In nat table, PREROUTING chain can only use -i and do dnat; POSTROUTING chain can only use -o and do snat. What you can do with the nat INPUT and OUTPUT chains I don’t understand well, but I think INPUT can do snat and OUTPUT can do dnat.
Difference of snat vs masquerade on nat POSTROUTING: 1) for snat you set the ip address, for masquerade you give an interface, and it uses the address from that interface. Also Masquerade assumes the connection will change ip address when it goes down and comes back up, so throws away all connections (contrack) information.