skip to content

A packet arrives on a Linux host's network interface. Which netfilter hooks does it traverse if it is addressed to a local process, and which if the host forwards it to another machine? Where does the routing decision sit in that sequence?

level: middleimportance: must knowfreq 72%

answer

  1. five hooks, three possible paths
  2. routing decision splits the flow
  3. local delivery and forwarding are exclusive
  4. rewriting the destination must precede routing
  5. locally generated traffic is routed first

basics

~20 s

Netfilter has five hooks. An arriving packet hits PREROUTING first; the routing decision then sends it either to INPUT and a local socket, or to FORWARD and then POSTROUTING on its way out. Locally generated packets take OUTPUT then POSTROUTING.

solid answer

~40 s

Every packet entering the stack hits `PREROUTING` before anything else looks at it. The kernel then makes the routing decision, and that decision splits the path in two: if the destination is a local address the packet goes to `INPUT` and up to the socket; if it is for someone else it goes to `FORWARD` and then `POSTROUTING` on the way out of the chosen interface. Packets a local process generates start with a routing decision, then `OUTPUT`, then `POSTROUTING`. So there are exactly three paths — in, through, and out — and only the forwarded one sees `FORWARD`. The position of the routing decision is why destination NAT has to happen in `PREROUTING`: routing must see the rewritten destination. Source NAT sits in `POSTROUTING`, after the outgoing interface is known.

go deeper

for a junior

Learn the five hook names and which chain covers traffic to the host, through the host, and from the host. Being able to place a rule in the right chain is the expectation here.

for a middle

Draw the path from memory and put the routing decision in the right place, then use it to explain why destination rewriting happens early and source rewriting happens late.

for a senior

Use the map as a diagnostic tool: given a rule that never matches or a NAT that sends traffic the wrong way, identify which of the three paths the packet actually takes and where the rule sits relative to routing.

for a principal

Reason about where policy belongs across a fleet — host-local filtering versus gateway forwarding versus what the network enforces — and about hosts where bridged or offloaded traffic bypasses the hooks you were counting on.

## The five hooks Netfilter places five hooks in the kernel's IP path. Both `iptables` chains and nftables base chains attach to them, and the classic chain names are the hook names: - **PREROUTING** — every packet that has just come off an interface and passed basic sanity checks, before the kernel has decided where it is going. - **INPUT** — packets the routing decision determined are addressed to this host. - **FORWARD** — packets the routing decision determined belong to some other host and that this machine will route onward. - **OUTPUT** — packets generated by a local process. - **POSTROUTING** — everything on its way out of an interface, whether forwarded or locally generated. ## The three paths **Inbound to a local process:** PREROUTING → routing decision → INPUT → socket. This is the path of an SSH connection to the box, or a request to a web server running on it. **Forwarded through the box:** PREROUTING → routing decision → FORWARD → POSTROUTING → wire. This is the path of a router, a NAT gateway, or a host bridging traffic for virtual machines. **Generated locally:** routing decision → OUTPUT → POSTROUTING → wire. Note the ordering: a locally generated packet is routed *before* OUTPUT, because the kernel needs a source address and an outgoing interface to construct the packet in the first place. Those paths are mutually exclusive. A packet that reaches INPUT will never reach FORWARD, which is why a rule written in FORWARD to protect a service running on this host does nothing at all — the classic way to convince yourself you have firewalled something when you have not. ## Why the routing decision's position matters The routing decision is not a hook, but it is the most important landmark in the diagram, because two things depend on being on the correct side of it. **Destination NAT must come before it.** If you rewrite the destination address after routing, the packet has already been assigned a path based on the *old* destination — it will be delivered locally or sent out the wrong interface. That is precisely why the DNAT verdict is only available in PREROUTING (for arriving traffic) and OUTPUT (for locally generated traffic). **Source NAT must come after it.** The whole point of source rewriting on a gateway is usually to make the packet appear to come from the address of the interface it is leaving by, and that interface is only known once routing has run. Hence SNAT and MASQUERADE live in POSTROUTING. There is a subtlety on the OUTPUT path: because a locally generated packet has already been routed when it reaches OUTPUT, a DNAT applied there forces the kernel to *re-run* the routing lookup afterwards, so the new destination is honoured. ## What runs at each hook Several tables can register at one hook, and the priority decides the order. At PREROUTING, for example, a packet passes raw, then connection tracking, then mangle, then destination NAT. At POSTROUTING it passes mangle and then source NAT. Filtering conventionally sits at priority 0 at INPUT, FORWARD and OUTPUT. ## Bridged traffic is different If the machine is switching frames between ports of a Linux bridge rather than routing them, that traffic does not traverse the IP hooks at all by default — it goes through the separate bridge hooks. Pushing bridged traffic through the IP hooks requires the `br_netfilter` module, which is a distinct behaviour worth knowing about because it surprises people who expect their IP firewall to see everything crossing the box. ## Reasoning with the map Once the map is internalised, a whole class of questions answers itself. Where do you block traffic to a service on this host? INPUT. Where do you block traffic between two networks this box routes? FORWARD. Where do you rewrite an inbound port to an internal server? PREROUTING. Where do you hide a private network behind one address? POSTROUTING. Why does a rule in a chain never match? Usually because the packet takes a different one of the three paths than you assumed.

  • Why does destination NAT have to be applied before the routing decision?
    Because routing selects the outgoing interface and next hop from the destination address. If the destination is rewritten afterwards, the packet has already been placed on a path chosen for the old address — typically delivered locally or sent out the wrong interface. That is why the DNAT verdict is only offered at PREROUTING and at OUTPUT, and why a DNAT at OUTPUT triggers a fresh routing lookup.
  • A rule blocking a port was added to FORWARD, yet the service on the host is still reachable. What happened?
    The traffic is addressed to the host itself, so the routing decision sent it down the local-delivery path: PREROUTING then INPUT. It never reaches FORWARD, which only sees packets being routed on behalf of another machine. The rule belongs in INPUT. Nothing about the rule is wrong except the chain.
  • Which hooks does a packet generated by a local process traverse?
    A routing decision first — the kernel needs a source address and an outgoing interface to build the packet — then OUTPUT, then POSTROUTING. It never sees PREROUTING or INPUT. This asymmetry is why filtering a host's own outbound traffic is done in OUTPUT while filtering what it accepts is done in INPUT.
  • Do packets switched between ports of a Linux bridge pass through the IP hooks?
    Not by default. Bridged frames traverse the bridge's own hooks, not the IP PREROUTING/FORWARD/POSTROUTING path, so an IP-level firewall does not see them. The `br_netfilter` module exists to push bridged traffic through the IP hooks, and it must be deliberately enabled — a common surprise when a firewall on a bridging host appears to be ignored.

saying these in an interview costs you the question

  • Thinks every packet passes through all five hooks
  • Puts rules for local services in the FORWARD chain
  • Believes routing happens before PREROUTING
  • Thinks locally generated packets traverse INPUT
  • Assumes POSTROUTING only sees forwarded traffic

context