'iptables -L' doesn't show you interface matches on rules by default
Today I learned something that I could have noticed if I'd paid
enough attention, which is that the default '
iptables -L' output
doesn't show you interface matches that are part of rules. In
order to see this in 'iptables -L' you have to make it verbose (with
-v), which also shows you the volume counters. There is a story
Normally I look at my iptables rules with '
iptables -vnL' (and
often a particular chain, like INPUT), or with '
-nL' if I'm planning to delete rules and want their line numbers.
Recently I noticed that libvirt was doing
some things to my iptables setup and I decided to scrub them all
out, which meant getting line numbers. When I did this, I saw what
I thought was a dangerous accept-all rule (which I
assumed was added by libvirt). In the 'iptables --line-numbers -nL'
output, things looked like this:
# iptables --line-numbers -nL INPUT Chain INPUT (policy ACCEPT) num target prot opt source destination 1 ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 [...]
I did various things to try to track this rule down and to remove
it reliably. Eventually I had a chance to look at the state of my
machine's iptables rules very soon after boot, where I used '
-vnL INPUT'. The rule was there, and at first I was irate. But
then I looked closer. In the verbose output there were some additional
# iptables -vnL INPUT Chain INPUT (policy ACCEPT [...]) pkts bytes target prot opt in out source destination NNN NNN ACCEPT all -- lo * 0.0.0.0/0 0.0.0.0/0 [...]
Oh. This dangerous looking rule was actually an 'allow all from loopback' rule to make sure that no local traffic was blocked by other, later rules. At the time I didn't realize that the basic 'iptables -L' output didn't contain this information, so I assumed that I had just failed to fully read output and had jumped to conclusions (it wouldn't be the first time).
(Then I was told and suddenly everything made much more sense.)
The somewhat less convenient alternative to 'iptables -L' is 'iptables -S', which is less readable but shows you the full rule as iptables understands things. For example:
# iptables -S INPUT -P INPUT ACCEPT -A INPUT -i lo -j ACCEPT [...]
I probably won't switch my habits to using 'iptables -S' for various reasons, but hopefully I'll remember it. If what I care about is the actual rules, I should probably use it over 'iptables -vnL'. Usually what I'm looking at is the traffic volume, though, and that requires 'iptables -vnL'.
The other drawback of 'iptables -S' is that there appears to be no way to get it to list line numbers. If you want to look for bad rules and delete them with line numbers, this leaves you to use 'iptables --line-numbers -vnL' or to go back and forth between 'iptables -S' (to see the exact rules) and 'iptables --line-numbers -vnL' (to get the line numbers for what you've determined you want to get rid of).
(I know, in the bright future we'll all be using nftables instead. The future isn't here yet and I'm sure nftables has its own issues, although I did recently do some firewall stuff through nftables on an Ubuntu 22.04 machine and it went okay.)