The policy on a built-in chain determines what happens to packets that make it through all the rules in the chain without matching a single one with a dispositive target. In your example above, packets that make it all the way through the FORWARD
chain without matching any rule with a dispositive target will be ACCEPT
ed, because the chain's policy is ACCEPT
.
User-defined chains cannot have a policy. Packets that pass all the way through a user-defined chain without matching a rule with a dispositive target return to the chain from which they were sent to the user-defined chain (the "calling chain") at the rule after the one that sent them there.
A dispositive target is one which disposes of a packet; examples include DROP
, ACCEPT
, and MASQUERADE
; non-dispositive targets include LOG
, and the null target (it's quite legal to have a rule that has no target). When a packet matches a rule with a dispositive target, the packet is considered disposed of, and no further rule processing occurs. When a packet matches a rule without a dispositive target, packet processing continues at the next rule.
An important corollary of this logic on target-matching and disposition is that first-dispositive-match wins. Too often we see questions on SF where people have a chain that says, eg,
Chain INPUT (policy ACCEPT 210 packets, 22621 bytes)
pkts bytes target prot opt in out source destination
3224K 1330M DROP tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:80
which contains a single rule to block access to a web server (tcp dpt:80
). They wish to allow a single external IP address, say 1.2.3.4
, to access this web server, so they add a rule with
iptables -A INPUT -p tcp --dport 80 -s 1.2.3.4 -j ACCEPT
and they end up with a chain like this
Chain INPUT (policy ACCEPT 210 packets, 22621 bytes)
pkts bytes target prot opt in out source destination
3224K 1330M DROP tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:80
0 0 ACCEPT tcp -- * * 1.2.3.4 0.0.0.0/0 tcp dpt:80
As you can see, the packet counts on that last rule are zero - and they will always be zero. No packet can match that last rule without having matched the one before it, and the one before it is dispositive (DROP
), so no packet will ever reach that last rule.
The way to deal with this correctly is to ensure that your exceptions come before your rules, like this:
Chain INPUT (policy ACCEPT 210 packets, 22621 bytes)
pkts bytes target prot opt in out source destination
20 875 ACCEPT tcp -- * * 1.2.3.4 0.0.0.0/0 tcp dpt:80
3224K 1330M DROP tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:80
Now, the exceptional acceptances are handled first, then other web server packets that don't come from the exceptional server are handled and dropped, and finally the chain policy takes care of all other packets and accepts them.