From: Florian Westphal <fw@strlen.de>
To: Mathias Dufresne <mathias.dufresne@gmail.com>
Cc: netfilter@vger.kernel.org
Subject: Re: Fwd: [nftables] is it possible to declare multiple tables for a given family type?
Date: Mon, 2 Mar 2026 00:53:37 +0100 [thread overview]
Message-ID: <aaTRgeXDaznuZvgh@strlen.de> (raw)
In-Reply-To: <fc37db9e-39ed-4478-bb53-887156e309b2@gmail.com>
Mathias Dufresne <mathias.dufresne@gmail.com> wrote:
> Le 2026-03-01 à 14:52, Florian Westphal a écrit :
> The goal would have been to have one table per service containing
> everything related to that specific service and nothing else.
I see. One way to do it is to include such sub-configurations
from a central ruleset file.
> > Just like in iptables, 'accept' in raw table just means packets
> > continue to travel through the stack, you need to accept them in mangle
> > and again in filter table.
> Do you meant the network stack or the nftables' rules stack?
The former. E.g. (staying with iptables, its same in nftables):
if a packet is accepted in mangle prerouting, it will continue and will
eventually make it to mangle input or forward.
> > Also, base chains (those with a line like
> > 'type filter hook input priority filter; policy accept;') always cause a
> > slow-down: they divert all packets into the nftables vm, so its a good idea to
> > minimize the amount of times this happens per packet.
>
> Again, I'm lost there... I'm certainly lacking the basic knowledge to
> understand :/
No problem. Consider an nftables ruleset that has ONLY
chain foo {
some rule ..
}
This ruleset is very fast. And useless. Because it never processes
any packets.
In iptables, this isn't possible, because all tables have
builtin-chains: PREROUTING, INPUT, and so on.
In nftables, one has to manually declare which chains are the 'starting
point' for packets passing through the networking stack.
E.g. type filter hook input priority filter; policy accept;
tells that you'd like semantics that are identical to iptables filter
INPUT chain: it will see incoming packets that have passed through the
routing step and are destined for the local host.
Makes sense so far?
This means, ALL incoming local packets will appear in this chain
(minus those that were dropped earlier on in the stack of course).
Example:
chain myinput {
type filter hook input priority filter; policy accept;
tcp dport 22 jump ssh
tcp dport { 80, 433 } jump httpd
}
...
... will be faster than making
'ssh' and 'httpd' two independent 'type filter hook input' chains.
Why? Because in the case above, all incoming packets pass though
'myinput', then only a small subset gets passed on to ssh and httpd,
respectively.
If you make the two user chains base chains ('type filter...', both reveive
all the traffic). In case you haven't tried it: See if 'nft list hooks'
provies some assistance to you.
> --------------------------------------------------------------------
>
> Here is a working single table to SSH the firewall and one LAN through
> that firewall:
>
> table ip filter_them_all {
> chain ip_log_svc_administrative_services/ssh {
> counter packets 0 bytes 0 log prefix "Accept ip SVC for
> 'administrative services/ssh': " group 2
> counter packets 0 bytes 0 accept
> }
> chain input {
> type filter hook input priority filter; policy accept;
> ct state {established,related} counter log prefix "ACCEPT CT for
> INPUT" group 2
> ct state {established,related} accept
> iif vdi-lan ip daddr 10.9.9.252/32 tcp dport 22 ct state new jump ip_log_svc_administrative_services/ssh
> iif vdi-lan oif svc-web ip daddr 10.54.80.0/24 tcp dport 22 ct state new jump ip_log_svc_administrative_services/ssh
> counter packets 0 bytes 0 log prefix "REFUSED INPUT packet as it reached the end of filtering rules stack." group 2
> counter packets 0 bytes 0 drop
> }
> chain forward {
> type filter hook forward priority filter; policy accept;
> ct state {established,related} counter log prefix "ACCEPT CT for > FORWARD" group 2
I'd suggest to add some rate limiting for your log lines.
> # these two are working and can't be omitted
> iif vdi-lan oif svc-web ip daddr 10.54.80.0/24 tcp dport 22 log prefix "ACCEPT FORWARD for ssh" group 2
> iif vdi-lan oif svc-web ip daddr 10.54.80.0/24 tcp dport 22 accept
If you don't want to limit, you can combine this into one line, you can
'log prefix ... accept' in nftables.
> chain output {
> type filter hook output priority filter; policy accept;
> ct state {established,related} counter log prefix "ACCEPT CT for
> OUTPUT" group 2
> ct state {established,related} accept
> counter packets 0 bytes 0 log prefix "REFUSED OUTPUT packet as it
> reached the end of filtering rules stack." group 2
> counter packets 0 bytes 0 drop
Are you sure you need output filtering? This prevents e.g. dns
resolution, ntp (time) refresh etc.
> table ip tracked_packets {
> chain input {
> type filter hook input priority 300; policy accept;
> ct state {established,related} counter log prefix "ACCEPT CT for
> INPUT" group 2
> ct state {established,related} accept
> }
> chain input {
> type filter hook input priority 310; policy accept;
> iif vdi-lan ip daddr 10.9.9.252/32 tcp dport 22 ct
> state new jump ip_log_svc_administrative_services/ssh
> iif vdi-lan oif svc-web ip daddr 10.54.80.0/24 tcp dport 22 ct
> state new jump ip_log_svc_administrative_services/ssh
> }
This works, but as you found there is no 'memory' and all chains have
to accept all packets for them to make it though.
> His this approach - several filtering tables - valid? I mean I could
> easily have made errors in the syntax...
Yes, but I don't consider it a good idea, I also don't think its suited
for what you have in mind.
If this is about enabling / disabling services, I would use a set for
that.
set s {
typeof iif . oif . ip daddr . meta l4proto . th dport
flags interval
}
chain forward {
# these two are working and can't be omitted
iif . oif . ip saddr . meta l4proto . th dport @s accept
[ totally untested, for illustrative purposes ... ]
next prev parent reply other threads:[~2026-03-01 23:53 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <752a3ecd-b379-4b82-8ac1-a64450e14167@gmail.com>
2026-03-01 18:59 ` Fwd: [nftables] is it possible to declare multiple tables for a given family type? Mathias Dufresne
2026-03-01 23:53 ` Florian Westphal [this message]
2026-03-02 15:32 ` Mathias Dufresne
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=aaTRgeXDaznuZvgh@strlen.de \
--to=fw@strlen.de \
--cc=mathias.dufresne@gmail.com \
--cc=netfilter@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox