2

I am new to nftables. I have read a few docs and went through the main wiki page and I still don't understand how the DOCKER-USER chain work.

Here is the table which was created by docker:

table ip filter {
        chain DOCKER {
        }

        chain DOCKER-ISOLATION-STAGE-1 {
                iifname "docker0" oifname != "docker0" counter packets 0 bytes 0 jump DOCKER-ISOLATION-STAGE-2
                counter packets 0 bytes 0 return
        }

        chain DOCKER-ISOLATION-STAGE-2 {
                oifname "docker0" counter packets 0 bytes 0 drop
                counter packets 0 bytes 0 return
        }

        chain FORWARD {
                type filter hook forward priority filter; policy drop;
                counter packets 15050 bytes 1456483 jump DOCKER-USER
                counter packets 0 bytes 0 jump DOCKER-ISOLATION-STAGE-1
                oifname "docker0" ct state related,established counter packets 0 bytes 0 accept
                oifname "docker0" counter packets 0 bytes 0 jump DOCKER
                iifname "docker0" oifname != "docker0" counter packets 0 bytes 0 accept
                iifname "docker0" oifname "docker0" counter packets 0 bytes 0 accept
        }

        chain DOCKER-USER {
                iifname "pub_br0" oifname "pub_br0" counter packets 15050 bytes 1456483 accept
                counter packets 0 bytes 0 return
        }
}

As you can see, the default policy of the FORWARD chain is "drop". Since my server does route to VMs as well, I had to insert a rule as the official doc said.

So the first line in DOCKER-USER was created by me.

The question is: Why does it work ? I read in the wiki page that "jump"ing to chain means that the control will return back to the caller chain, where my packet should have been dropped by the default policy.

What did I miss, why was my packet from pub_br0 to pub_br0 not dropped in docker's FORWARD chain?

Thanks

Mitya
  • 128
  • 5

1 Answers1

0

The chain's policy only takes effect if the packet reaches the end of that chain without matching any rule that has an absolute verdict statement, i.e. accept or drop.

If a packet matches a rule with a drop verdict, or reaches the end of a base chain with policy drop, it's immediately gone forever; but if a packet gets an accept verdict, it still has to go through any other base chains that might be associated with the same hook with a higher priority number, and any chains in other applicable hooks that may come after it in the package processing pipeline. Those other chains might still drop the packet.

So, your FORWARD base chain has policy drop. That only means if a packet reaches the end of the FORWARD chain, it will be dropped. But the first rule in the chain matches everything and jumps to the DOCKER-USER chain, so your packet will be processed by that chain first.

In the DOCKER-USER chain, the first rule matches packets that came in via pub_br0 and are going right out through the same bridge. Your packet matches, and the verdict is accept. That terminates the ruleset evaluation: no need to process any further in the DOCKER-USER chain, nor process the rest of the FORWARD chain; and since there seems to be no other filter base chains associated with hook forward, and no base chains of any type with hook postrouting, we're done and the packet is accepted for forwarding.

If the first rule in the DOCKER-USER chain does not match, the next rule is just a counter and an explicit return, so anything that does not match the first rule in the DOCKER-USER chain would go right back to be processed through the rest of the chain that sent us to DOCKER-USER, i.e. the FORWARD chain in this case.

But the counter for that rule currently reads packets 0 bytes 0, so everything that's arrived into the DOCKER-USER chain so far must have been accepted by the first rule in the chain, because they haven't had a chance to reach the return rule.

telcoM
  • 4,448
  • 15
  • 25
  • Thank you telcoM for your answer. Ok, so when a packet gets accepted by a rule in a regular chain than it means that it finishes the whole base chain operation and will call the next base chain (if there is any) with higher priority. Got it, thank you very much ! – Mitya Mar 16 '23 at 08:14