Re: [nftables/nft] nft equivalent of "ipset test"

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Wed, 18 Oct 2023 11:54:30 +0200
"U.Mutlu" <um@xxxxxxxxxxx> wrote:

> Pablo Neira Ayuso wrote on 10/18/23 11:36:
> > On Tue, Oct 17, 2023 at 08:00:57PM -0400, imnozi@xxxxxxxxx wrote:
> >> On Wed, 18 Oct 2023 00:36:37 +0200
> >> "U.Mutlu" <um@xxxxxxxxxxx> wrote:
> >>
> >>> ...
> >>> Actualy I need to do this monster:   :-)
> >>>
> >>> IP="1.2.3.4"
> >>> ! nft "get element inet mytable myset  { $IP }" > /dev/null 2>&1 && \
> >>> ! nft "get element inet mytable myset2 { $IP }" > /dev/null 2>&1 && \
> >>>     nft "add element inet mytable myset  { $IP }"
> >>
> >> Try using '||', akin to:
> >
> > Please, use 'nft create' for this, no need for an explicit test and
> > then add from command line.
> >
> > The idiom above is an antipattern, because it is not atomic, the
> > 'create' command provides a way to first test if the element exists
> > (if so it fails) then add it.
> 
> Pablo, unfortunately your solution with 'create' cannot be used
> in my above said special use-case of testing first in BOTH sets...
> 
> I just don't understand why the author cannot simply add a real 'test' 
> function to the nft tool...

One a feature has been added, it usually has to be maintained forever so it is to be expected that the use case has to be strongly justified. In my opinion, the principal shortcomings of "get element" are twofold.

Firstly, there is no way to distinguish between nft(8) failing because it did not find the specified element or for some other, wholly unrelated, reason. In both cases, the exit status is likely to be 1. That makes it a poor interface. One solution could be for nft to at least promise to exit >=2 in the case of syntax errors, syscall failures etc.

Secondly, the use of "get element" entails spewing a diagnostic message to STDERR in the case that the element isn't found. The user is thus presented with the unenviable choice of silencing STDERR. This is a bad thing because, in doing so, *all* errors and dignostics will be silenced.

Now, as concerns the matter of producing monstrosities, there is always the option to write the code in a more elegant fashion. One way would be to compose a function.

in_all_sets() {
	local ip=$1 set
	shift
	for set; do
		nft -t "get element $set { $ip }" >/dev/null 2>&1 || return
	done
}

if ! in_all_sets "$ip" "inet mytable myset" "inet mytable myset"; then
	nft "add element inet mytable myset { $ip }"
fi

Of course, this does not address the aformentioned shortcomings of the interface but the legibility and maintainability of the code is improved.

Another would be to apply the redirections to a compound command.

{
	# Neither of the following will be seen
	echo "stdout"
	echo "stderr" >&2
} >/dev/null 2>&1

Though Pablo already mentioned it, the overall approach amounts to a TOCTOU race. The prospect of being able to atomically check for the existence of an element in multiple sets is a curious one. I, too, would be interested in understanding the underlying use case.

-- 
Kerin Millar



[Index of Archives]     [Linux Netfilter Development]     [Linux Kernel Networking Development]     [Netem]     [Berkeley Packet Filter]     [Linux Kernel Development]     [Advanced Routing & Traffice Control]     [Bugtraq]

  Powered by Linux