'iptables -L' doesn't show you interface matches on rules by default

July 15, 2022

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 here.

Normally I look at my iptables rules with 'iptables -vnL' (and often a particular chain, like INPUT), or with 'iptables --line-numbers -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  --

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 'iptables -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 fields:

# iptables -vnL INPUT
Chain INPUT (policy ACCEPT [...])
 pkts bytes  target prot opt in  out source     destination         
  NNN   NNN  ACCEPT all  --  lo  *

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
-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.)

Comments on this page:

By Michael at 2022-07-16 04:19:47:

It's been a while since I did anything much with iptables, but doesn't it support -D for delete in place of -A for append? That seems like it should work unless you need to do something weird like delete only the second instance of two identical rules within a chain.

So you would take the rule from the iptables -S output

   -A INPUT -i lo -j ACCEPT

replace -A with -D

   -D INPUT -i lo -j ACCEPT

and stick iptables at the beginning:

   # iptables -D INPUT -i lo -j ACCEPT

and it will delete that rule, regardless of its position within the chain, and not risk a race condition between a chain-modifying process (which might cause rules to be renumbered) and the manual deletion.

By cks at 2022-07-18 15:47:39:

I generally consider deleting by rule number to be more reliable than trying to reconstruct the rule from the output of 'iptables -L'. With the rule number approach I know exactly what I'm removing; with -D, I have to believe that I've reconstructed the rule accurately and written it out properly. As this entry shows, that might actually be tricky with the default 'iptables -L' output, since it hides the interfaces involved and two rules might differ only in what interfaces they work on.

(Using 'iptables -S' output would remove this problem, but then I have to remember to use it.)

Written on 15 July 2022.
« IMAP servers can have significant imbalances between disk and network IO
How to get (or recognize) a common Unix log timestamp format in things »

Page tools: View Source, View Normal, Add Comment.
Login: Password:
Atom Syndication: Recent Comments.

Last modified: Fri Jul 15 22:50:57 2022
This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.