]> git.ipfire.org Git - thirdparty/nftables.git/log
thirdparty/nftables.git
4 months agoevaluate: reject unsupported expressions in payload statement for bitfields
Pablo Neira Ayuso [Fri, 28 Feb 2025 14:57:18 +0000 (15:57 +0100)] 
evaluate: reject unsupported expressions in payload statement for bitfields

The payload statement evaluation pretends that it can handle any
expression for bitfields, but the existing evaluation code only knows
how to handle value expression.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
4 months agoevaluate: simplify payload statement evaluation for bitfields
Pablo Neira Ayuso [Fri, 28 Feb 2025 14:55:04 +0000 (15:55 +0100)] 
evaluate: simplify payload statement evaluation for bitfields

Instead of allocating a lshift expression and relying on the binary
operation transfer propagate this to the mask value, lshift the mask
value immediately.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
4 months agoevaluate: release existing datatype when evaluating unary expression
Pablo Neira Ayuso [Fri, 28 Feb 2025 14:54:55 +0000 (15:54 +0100)] 
evaluate: release existing datatype when evaluating unary expression

Use __datatype_set() to release the existing datatype before assigning
the new one, otherwise ASAN reports the following memleak:

Direct leak of 104 byte(s) in 1 object(s) allocated from:
    #0 0x7fbc8a2b89cf in __interceptor_malloc ../../../../src/libsa
    #1 0x7fbc898c96c2 in xmalloc src/utils.c:31
    #2 0x7fbc8971a182 in datatype_clone src/datatype.c:1406
    #3 0x7fbc89737c35 in expr_evaluate_unary src/evaluate.c:1366
    #4 0x7fbc89758ae9 in expr_evaluate src/evaluate.c:3057
    #5 0x7fbc89726bd9 in byteorder_conversion src/evaluate.c:243
    #6 0x7fbc89739ff0 in expr_evaluate_bitwise src/evaluate.c:1491
    #7 0x7fbc8973b4f8 in expr_evaluate_binop src/evaluate.c:1600
    #8 0x7fbc89758b01 in expr_evaluate src/evaluate.c:3059
    #9 0x7fbc8975ae0e in stmt_evaluate_arg src/evaluate.c:3198
    #10 0x7fbc8975c51d in stmt_evaluate_payload src/evaluate.c:330

Fixes: faa6908fad60 ("evaluate: clone unary expression datatype to deal with dynamic datatype")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
4 months agodoc: add mptcp to tcp option matching list
Florian Westphal [Thu, 6 Mar 2025 04:19:15 +0000 (05:19 +0100)] 
doc: add mptcp to tcp option matching list

Suggested-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: Florian Westphal <fw@strlen.de>
4 months agosegtree: fix string data initialisation
Florian Westphal [Wed, 5 Mar 2025 15:01:48 +0000 (16:01 +0100)] 
segtree: fix string data initialisation

This uses the wrong length.  This must re-use the length of the datatype,
not the string length.

The added test cases will fail without the fix due to erroneous
overlap detection, which in itself is due to incorrect sorting of
the elements.

Example error:
 netlink: Error: interval overlaps with an existing one
 add element inet testifsets simple_wild {  "2-1" } failed.
 table inet testifsets {
      ...       elements = { "1-1", "abcdef*", "othername", "ppp0" }

... but clearly "2-1" doesn't overlap with any existing members.
The false detection is because of the "acvdef*" wildcard getting sorted
at the beginning of the list which is because its erronously initialised
as a 64bit number instead of 128 bits (16 bytes / IFNAMSIZ).

Fixes: 5e393ea1fc0a ("segtree: add string "range" reversal support")
Signed-off-by: Florian Westphal <fw@strlen.de>
Reviewed-by: Pablo Neira Ayuso <pablo@netfilter.org>
4 months agoexpression: expr_build_udata_recurse should recurse
Florian Westphal [Thu, 27 Feb 2025 14:52:10 +0000 (15:52 +0100)] 
expression: expr_build_udata_recurse should recurse

If we see EXPR_BINOP, recurse: ->left can be another EXPR_BINOP.

This is irrelevant for 'typeof' named sets, but for anonymous sets, the
key is derived from the concat expression that builds the lookup key for
the anonymous set.

 tcp option mptcp subtype . ip daddr { mp-join. 10.0.0.1, ..

 needs two binops back-to-back:

  [ exthdr load tcpopt 1b @ 30 + 2 => reg 1 ]
  [ bitwise reg 1 = ( reg 1 & 0x000000f0 ) ^ 0x00000000 ]
  [ bitwise reg 1 = ( reg 1 >> 0x00000004 ) ]

This bug prevents concat_expr_build_udata() from creating the userdata key
at load time.

When listing the rules, we get an assertion:
 nft: src/mergesort.c:23: concat_expr_msort_value: Assertion `ilen > 0' failed.

because the set has a key with 0-length integers.

Signed-off-by: Florian Westphal <fw@strlen.de>
4 months agonetlink_delinearize: also consider exthdr type when trimming binops
Florian Westphal [Thu, 27 Feb 2025 14:52:09 +0000 (15:52 +0100)] 
netlink_delinearize: also consider exthdr type when trimming binops

This allows trimming the binop for exthdrs, this will make nft render
   (tcp option mptcp unknown & 240) >> 4 . ip saddr @s1

as
    tcp option mptcp subtype . ip saddr @s1

Also extend the typeof set tests with a set concatenating a
sub-byte-sized exthdr expression with a payload one.

The additional call to expr_postprocess() is needed, without this,
typeof_sets_0.nft fails because
  frag frag-off @s4 accept

is shown as
 meta nfproto ipv6 frag frag-off @s4 accept

Previouly, EXPR_EXTHDR would cause payload_binop_postprocess()
to return false which will then make the caller invoke
expr_postprocess(), but after handling EXPR_EXTHDR this doesn't happen
anymore.

Signed-off-by: Florian Westphal <fw@strlen.de>
4 months agoexpression: propagate key datatype for anonymous sets
Florian Westphal [Thu, 27 Feb 2025 14:52:08 +0000 (15:52 +0100)] 
expression: propagate key datatype for anonymous sets

set s {
  typeof tcp option mptcp subtype
  elements = { mp-join, dss }
}

is listed correctly. The set key provides the 'mptcpopt_subtype'
information and listing can print all elements with symbolic names.

In anon set case this doesn't work:
  tcp option mptcp subtype { mp-join, dss }

is printed as "... subtype { 1, 2}" because the anon set only provides
plain integer type.

This change propagates the datatype to the individual members of the
anon set.

After this change, multiple existing data types such as TYPE_ICMP_TYPE
could theoretically be replaced by integer-type aliases.

However, those datatypes are already exposed to userspace via the
'set type' keyword.  Thus removing them will break set definitions that
use them.

Signed-off-by: Florian Westphal <fw@strlen.de>
4 months agotcpopt: add symbol table for mptcp suboptions
Florian Westphal [Thu, 27 Feb 2025 14:52:07 +0000 (15:52 +0100)] 
tcpopt: add symbol table for mptcp suboptions

nft can be used t match on specific multipath tcp subtypes:

  tcp option mptcp subtype 0

However, depending on which subtype to match, users need to look up the
type/value to use in rfc8684. Add support for mnemonics and
"nft describe tcp option mptcp subtype" to get the subtype list.

Because the number of unique 'enum datatypes' is limited by ABI contraints
this adds a new mptcp suboption type as integer alias.

After this patch, nft supports all of the following:
 add element t s { mp-capable }
 add rule t c tcp option mptcp subtype mp-capable
 add rule t c tcp option mptcp subtype { mp-capable, mp-fail }

For the 3rd case, listing will break because unlike for named sets, nft
lacks the type information needed to pretty-print the integer values,
i.e. nft will print the 3rd rule as 'subtype { 0, 6 }'.

This is resolved in a followup patch.

Other problematic constructs are:
  set s1 {
    typeof tcp option mptcp subtype . ip saddr
    elements = { mp-fail . 1.2.3.4 }
  }

Followed by:
  tcp option mptcp subtype . ip saddr @s1

nft will print this as:
  tcp option mptcp unknown & 240) >> 4 . ip saddr @s1

All of these issues are not related to this patch, however, they also occur
with other bit-sized extheader fields.

Signed-off-by: Florian Westphal <fw@strlen.de>
4 months agopayload: don't kill dependency for proto_th
Florian Westphal [Thu, 27 Feb 2025 10:47:02 +0000 (11:47 +0100)] 
payload: don't kill dependency for proto_th

proto_th carries no information about the proto number, we need to
preserve the L4 protocol expression unless we can be sure that

For example, if "meta l4proto 91 @th,0,16 0" is simplified to
"th sport 0", the information of protocol number is lost.

Based on initial patch from Xiao Liang.

Signed-off-by: Xiao Liang <shaw.leon@gmail.com>
Signed-off-by: Florian Westphal <fw@strlen.de>
Reviewed-by: Pablo Neira Ayuso <pablo@netfilter.org>
4 months agotests: remove temporary file
Florian Westphal [Tue, 4 Mar 2025 15:11:57 +0000 (16:11 +0100)] 
tests: remove temporary file

0002-relative leaves a temporary file in the current working
directory, at the time the "trap" argument is expanded, tmpfile2
isn't set.

Signed-off-by: Florian Westphal <fw@strlen.de>
Acked-by: Pablo Neira Ayuso <pablo@netfilter.org>
4 months agotests: add atomic chain replace test
Florian Westphal [Sun, 2 Mar 2025 06:50:27 +0000 (07:50 +0100)] 
tests: add atomic chain replace test

Add a test that replaces one base chain and check that no
filtered packets make it through, i.e. that the 'old chain'
doesn't disappear before new one is active.

Acked-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: Florian Westphal <fw@strlen.de>
4 months agobuild: add hint for a2x error message
Jan Engelhardt [Fri, 28 Feb 2025 18:54:05 +0000 (19:54 +0100)] 
build: add hint for a2x error message

Display:

  a2x not found, please install asciidoc, or pass --disable-man-doc

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
5 months agopayload: honor inner payload description in payload_expr_cmp()
Pablo Neira Ayuso [Tue, 25 Feb 2025 23:39:01 +0000 (00:39 +0100)] 
payload: honor inner payload description in payload_expr_cmp()

payload comparison must consider inner_desc.

No test update because I could not find any specific bug related to
this. I found it through source code inspection.

Fixes: 772892a018b4 ("src: add vxlan matching support")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: Florian Westphal <fw@strlen.de>
5 months agopayload: return early if dependency is not a payload expression
Florian Westphal [Tue, 25 Feb 2025 20:13:33 +0000 (21:13 +0100)] 
payload: return early if dependency is not a payload expression

 if (dep->left->payload.base != PROTO_BASE_TRANSPORT_HDR)

is legal only after checking that ->left points to an
EXPR_PAYLOAD expression. The dependency store can also contain
EXPR_META, in this case we access a bogus part of the union.

The payload_may_dependency_kill_icmp helper can't handle a META
dep either, so return early.

Fixes: 533565244d88 ("payload: check icmp dependency before removing previous icmp expression")
Signed-off-by: Florian Westphal <fw@strlen.de>
Reviewed-by: Pablo Neira Ayuso <pablo@netfilter.org>
5 months agopayload: remove double-store
Florian Westphal [Tue, 25 Feb 2025 20:12:29 +0000 (21:12 +0100)] 
payload: remove double-store

This assignment was duplicated.

Signed-off-by: Florian Westphal <fw@strlen.de>
Reviewed-by: Pablo Neira Ayuso <pablo@netfilter.org>
5 months agoevaluate: consolidate evaluation of symbol range expression
Pablo Neira Ayuso [Fri, 21 Feb 2025 23:56:32 +0000 (00:56 +0100)] 
evaluate: consolidate evaluation of symbol range expression

Expand symbol_range to range expression to consolidate evaluation.

I found a bug when testing for negative ranges:

  test.nft:5:16-30: Error: Could not process rule: File exists
                  elements = { 1.1.1.1-1.1.1.0 }
                               ^^^^^^^^^^^^^^^

after this patch, error reporting has been restored:

  test.nft:5:16-30: Error: Range negative size
                  elements = { 1.1.1.1-1.1.1.0 }
                               ^^^^^^^^^^^^^^^

Fixes: 347039f64509 ("src: add symbol range expression to further compact intervals")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
5 months agoevaluate: optimize zero length range
Pablo Neira Ayuso [Fri, 21 Feb 2025 23:32:11 +0000 (00:32 +0100)] 
evaluate: optimize zero length range

A rule like the following:

  ... tcp dport 22-22 ...

results in a range expression to match from 22 to 22.

Simplify to singleton value so a cmp is used instead.

This optimization already exists in set elements which might explain
this overlook.

Fixes: 7a6e16040d65 ("evaluate: allow for zero length ranges")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
5 months agotests: shell: random interval set with size
Pablo Neira Ayuso [Mon, 6 Jan 2025 21:56:32 +0000 (22:56 +0100)] 
tests: shell: random interval set with size

Generate a random set with intervals to validate set size, try one that
should fit and then subtract one to set size and retry.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
5 months agotests: shell: interval sets with size
Pablo Neira Ayuso [Mon, 6 Jan 2025 20:48:56 +0000 (21:48 +0100)] 
tests: shell: interval sets with size

Exercise size in set with intervals (rbtree), including corner cases
such as 0.0.0.0 and 255.255.255.255 (half-open interval).

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
5 months agofib: Change data type of fib oifname to "ifname"
Xiao Liang [Tue, 25 Feb 2025 10:02:17 +0000 (18:02 +0800)] 
fib: Change data type of fib oifname to "ifname"

Change data type of fib oifname from "string" to "ifname", so that it
can be matched against a set of ifnames:

    set x {
            type ifname
    }
    chain y {
            fib saddr oifname @x drop
    }

Signed-off-by: Xiao Liang <shaw.leon@gmail.com>
Signed-off-by: Florian Westphal <fw@strlen.de>
5 months agoparser_bison: get rid of unneeded statement
Florian Westphal [Mon, 24 Feb 2025 17:52:11 +0000 (18:52 +0100)] 
parser_bison: get rid of unneeded statement

Was used for the legacy flow statement, but that was removed in
2ee93ca27ddc ("parser_bison: remove deprecated flow statement")

Signed-off-by: Florian Westphal <fw@strlen.de>
Reviewed-by: Pablo Neira Ayuso <pablo@netfilter.org>
5 months agoevaluate: auto-merge is only available for singleton interval sets
Pablo Neira Ayuso [Thu, 20 Feb 2025 16:55:15 +0000 (17:55 +0100)] 
evaluate: auto-merge is only available for singleton interval sets

auto-merge is only available to interval sets with one value only,
untoggle this flag for concatenation with intervals.

Later, this can be hardened to reject it.

Fixes: 30f667920601 ("src: add 'auto-merge' option to sets")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
5 months agonetlink_linearize: use range expression for OP_EQ and OP_IMPLICIT
Pablo Neira Ayuso [Mon, 17 Feb 2025 09:23:24 +0000 (10:23 +0100)] 
netlink_linearize: use range expression for OP_EQ and OP_IMPLICIT

range expression is available since v4.9-rc1~127^2~67^2~3, replace the
two cmp expression when generating netlink bytecode.

Code to delinearize the two cmp expressions to represent the range
remains in place for backwards compatibility.

The delinearize path to parse range expressions with NFT_OP_EQ is
already present since:

 3ed932917cc7 ("src: use new range expression for != [a,b] intervals")

Update tests/py payload accordingly, json tests need no update since
they already use the range to represent them.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
5 months agosrc: add symbol range expression to further compact intervals
Pablo Neira Ayuso [Thu, 13 Feb 2025 17:56:46 +0000 (18:56 +0100)] 
src: add symbol range expression to further compact intervals

Update parser to use a new symbol range expression with smaller memory
footprint than range expression + two symbol expressions.

The evaluation step translates this into EXPR_RANGE_VALUE for interval
sets.

Note that maps or concatenations still use the less compact range
expressions representation, those require more work to use this new
symbol range expression. The parser also uses the classic range
expression if variables are used.

Testing with a 100k intervals, worst case scenario: no prefix or
singleton elements. This shows a reduction from 49.58 Mbytes to
35.47 Mbytes (-29.56% memory footprint for this case).

This follow up work to previous commits:

 91dc281a82ea ("src: rework singleton interval transformation to reduce memory consumption")
 c9ee9032b0ee ("src: add EXPR_RANGE_VALUE expression and use it")

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
5 months agoparser_bison: compact and simplify list and reset syntax
Florian Westphal [Thu, 16 Jan 2025 08:32:01 +0000 (09:32 +0100)] 
parser_bison: compact and simplify list and reset syntax

Works:
list sets
list sets inet
list sets table inet foo

Doesn't work:
list sets inet foo

Same for "list counters", "list quotas", etc.

"reset" keyword however supports this:
reset counters inet foo

and aliased this to
reset counters table inet foo

This is inconsistent and not inuitive.

Moreover, unlike "list sets", "list maps" only supported "list maps" and
"list maps inet", without the ability to only list maps of a given table.

Compact this to unify the syntax so it becomes possible to omit the "table"
keyword for either reset or list mode.

flowtables, secmarks and synproxys keywords are updated too.  "flow table"
and "meters" are NOT changed since both of these are deprecated in favor
of standard nft sets.

Reported-by: Slavko <linux@slavino.sk>
Signed-off-by: Florian Westphal <fw@strlen.de>
Reviewed-by: Pablo Neira Ayuso <pablo@netfilter.org>
5 months agoparser_bison: turn redundant ip option type field match into boolean
Pablo Neira Ayuso [Fri, 31 Jan 2025 10:14:22 +0000 (11:14 +0100)] 
parser_bison: turn redundant ip option type field match into boolean

The ip option expression allows for non-sense matching like:

ip option lsrr type 1

because 'lsrr' already provides the type field, this never results in a
matching.

Turn this expression into:

ip option lsrr exists

And update documentation to hide this redundant type field.

Fixes: 226a0e072d5c ("exthdr: add support for matching IPv4 options")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
5 months agoipopt: use ipv4 address datatype for address field in ip options
Pablo Neira Ayuso [Thu, 30 Jan 2025 18:39:20 +0000 (19:39 +0100)] 
ipopt: use ipv4 address datatype for address field in ip options

So user does not have to play integer arithmetics to match on IPv4
address.

Before:

 # nft describe ip option lsrr addr
 exthdr expression, datatype integer (integer), 32 bits

After:

 # nft describe ip option lsrr addr
 exthdr expression, datatype ipv4_addr (IPv4 address) (basetype integer), 32 bits

Fixes: 226a0e072d5c ("exthdr: add support for matching IPv4 options")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
5 months agodatatype: clamp boolean value to 0 and 1
Pablo Neira Ayuso [Fri, 31 Jan 2025 11:54:32 +0000 (12:54 +0100)] 
datatype: clamp boolean value to 0 and 1

If user provides a numeric value larger than 0 or 1, match never
happens:

 # nft --debug=netlink add rule x y tcp option sack-perm 4
 ip x y
  [ exthdr load tcpopt 1b @ 4 + 0 present => reg 1 ]
  [ cmp eq reg 1 0x00000004 ]

After this update:

 # nft --debug=netlink add rule x y tcp option sack-perm 4
 ip x y
  [ exthdr load tcpopt 1b @ 4 + 0 present => reg 1 ]
  [ cmp eq reg 1 0x00000001 ]

This is to address a rare corner case, in case user specifies the
boolean value through the integer base type.

Fixes: 9fd9baba43c8 ("Introduce boolean datatype and boolean expression")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
5 months agoexthdr: incomplete type 2 routing header definition
Pablo Neira Ayuso [Tue, 28 Jan 2025 20:48:19 +0000 (21:48 +0100)] 
exthdr: incomplete type 2 routing header definition

Add missing type 2 routing header definition.

Listing is not correct because these IPv6 extension header are still
lacking context to properly delinearize the listing, but at least this
does not crash anymore.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
5 months agotests: shell: delete netdev chain after test
Pablo Neira Ayuso [Wed, 15 Jan 2025 22:41:24 +0000 (23:41 +0100)] 
tests: shell: delete netdev chain after test

This update is needed for kernel patch:

  ("netfilter: nf_tables: Tolerate chains with no remaining hooks")

otherwise this hits DUMP FAILED in newer kernels.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
5 months agotests: py: extend raw payload match tests
Florian Westphal [Thu, 30 Jan 2025 17:47:14 +0000 (18:47 +0100)] 
tests: py: extend raw payload match tests

Add more test cases to exercise binop elimination for raw
payload matches.

Signed-off-by: Florian Westphal <fw@strlen.de>
Reviewed-by: Pablo Neira Ayuso <pablo@netfilter.org>
5 months agosrc: add and use payload_expr_trim_force
Florian Westphal [Thu, 30 Jan 2025 17:47:13 +0000 (18:47 +0100)] 
src: add and use payload_expr_trim_force

Previous commit fixed erroneous handling of raw expressions when RHS sets
a zero value.

Input: @ih,58,6 set 0 @ih,86,6 set 0 @ih,170,22 set 0
Output:@ih,48,16 set @ih,48,16 & 0xffc0 @ih,80,16 set \
@ih,80,16 & 0xfc0f @ih,160,32 set @ih,160,32 & 0xffc00000

After this patch, this will instead display:

@ih,58,6 set 0x0 @ih,86,6 set 0x0 @ih,170,22 set 0x0

payload_expr_trim_force() only works when the payload has no known
protocol (template) attached, i.e. will be printed as raw payload syntax.

It performs sanity checks on @mask and then adjusts the payload expression
length and offset according to the mask.

Also add this check in __binop_postprocess() so we can also discard masks
when matching, e.g.

'@ih,7,5 2' becomes '@ih,7,5 0x2', not '@ih,0,16 & 0xffc0 == 0x20'.

binop_postprocess now returns if it performed an action or not; if this
returns true then arguments might have been freed so callers must no longer
refer to any of the expressions attached to the binop.

Next patch adds test cases for this.

Signed-off-by: Florian Westphal <fw@strlen.de>
Reviewed-by: Pablo Neira Ayuso <pablo@netfilter.org>
5 months agonetlink_delinarize: fix bogus munging of mask value
Florian Westphal [Thu, 30 Jan 2025 17:47:12 +0000 (18:47 +0100)] 
netlink_delinarize: fix bogus munging of mask value

Given following input:
table ip t {
 chain c {
  @ih,58,6 set 0 @ih,86,6 set 0 @ih,170,22 set 0
 }
}

nft will produce following output:
chain c {
 @ih,48,16 set @ih,48,16 & 0x3f @ih,80,16 set @ih,80,16 & 0x3f0 @ih,160,32 set @ih,160,32 & 0x3fffff
}

The input side is correct, the generated expressions sent to kernel are:

1  [ payload load 2b @ inner header + 6 => reg 1 ]
2  [ bitwise reg 1 = ( reg 1 & 0x0000c0ff ) ^ 0x00000000 ]
3  [ payload write reg 1 => 2b @ inner header + 6 .. ]
4  [ payload load 2b @ inner header + 10 => reg 1 ]
5  [ bitwise reg 1 = ( reg 1 & 0x00000ffc ) ^ 0x00000000 ]
6  [ payload write reg 1 => 2b @ inner header + 10 .. ]
7  [ payload load 4b @ inner header + 20 => reg 1 ]
8  [ bitwise reg 1 = ( reg 1 & 0x0000c0ff ) ^ 0x00000000 ]
9  [ payload write reg 1 => 4b @ inner header + 20 .. ]

@ih,58,6 set 0 <- Zero 6 bits, starting with bit 58

Changes to inner header mandate a checksum update, which only works for
even byte counts (except for last byte in the payload).

Thus, we load 2b at offet 6. (16bits, offset 48).

Because we want to zero 6 bits, we need a mask that retains 10 bits and
clears 6: b1111111111000000 (first 8 bit retains 48-57, last 6 bit clear
58-63).  The '0xc0ff' is not correct, but thats because debug output comes
from libnftnl which prints values in host byte order, the value will be
interpreted as big endian on kernel side, so this will do the right thing.

Next, same problem:

@ih,86,6 set 0 <- Zero 6 bits, starting with bit 86.

nft needs to round down to even-sized byte offset, 10, then retain first
6 bits (80 + 6 == 86), then clear 6 bits (86-91), then keep 4 more as-is
(92-95).

So mask is 0xfc0f (in big endian) would be correct (b1111110000001111).

Last expression, @ih,170,22 set 0, asks to clear 22 bits starting with bit
170, nft correctly rounds this down to a 32 bit read at offset 160.

Required mask keeps first 10 bits, then clears 22
(b11111111110000000000000000000000).  Required mask would be 0xffc00000,
which corresponds to the wrong-endian-printed value in line 8 above.

Now that we convinced ourselves that the input side is correct, fix up
netlink delinearize to undo the mask alterations if we can't find a
template to print a human-readable payload expression.

With this patch, we get this output:

  @ih,48,16 set @ih,48,16 & 0xffc0 @ih,80,16 set @ih,80,16 & 0xfc0f @ih,160,32 set @ih,160,32 & 0xffc00000

... which isn't ideal.  We should fixup the payload expression to display
the same output as the input, i.e. adjust payload->len and offset as per
mask and discard the mask instead.

This will be done in a followup patch.

Fixes: 50ca788ca4d0 ("netlink: decode payload statment")
Reported-by: Sunny73Cr <Sunny73Cr@protonmail.com>
Signed-off-by: Florian Westphal <fw@strlen.de>
Reviewed-by: Pablo Neira Ayuso <pablo@netfilter.org>
6 months agoevaluate: allow to re-use existing metered set
Florian Westphal [Wed, 22 Jan 2025 09:18:04 +0000 (10:18 +0100)] 
evaluate: allow to re-use existing metered set

Blamed commit translates old meter syntax (which used to allocate an
anonymous set) to dynamic sets.

A side effect of this is that re-adding a meter rule after chain was
flushed results in an error, unlike anonymous sets named sets are not
impacted by the flush.

Refine this: if a set of the same name exists and is compatible, then
re-use it instead of returning an error.

Also pick up the reproducer kindly provided by the reporter and place it
in the shell test directory.

Fixes: b8f8ddfff733 ("evaluate: translate meter into dynamic set")
Reported-by: Yi Chen <yiche@redhat.com>
Signed-off-by: Florian Westphal <fw@strlen.de>
6 months agotests: shell: use mount --bind to change cgroupsv2 root
Pablo Neira Ayuso [Thu, 16 Jan 2025 13:26:31 +0000 (14:26 +0100)] 
tests: shell: use mount --bind to change cgroupsv2 root

Instead of remount which fails with SKIP in one of my test boxes because
cgroupsv2 rootfs is busy.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
6 months agoevaluate: remove variable shadowing
Pablo Neira Ayuso [Mon, 13 Jan 2025 16:28:19 +0000 (17:28 +0100)] 
evaluate: remove variable shadowing

unsigned int i is already declared in resolve_ll_protocol_conflict(),
remove it.

Fixes: 3a734d608131 ("evaluate: don't assert on net/transport header conflict")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
6 months agoscanner: better error reporting for CRLF line terminators
Pablo Neira Ayuso [Mon, 6 Jan 2025 23:00:50 +0000 (00:00 +0100)] 
scanner: better error reporting for CRLF line terminators

Provide a hint to users that file is coming with CRLF line terminators,
maybe from a non-Linux OS.

Extend scanner.l to provide hint on CRLF in files:

 # file test.nft
 test.nft: ASCII text, with CRLF, LF line terminators
 # nft -f test.nft
 test.nft:1:13-14: Error: syntax error, unexpected CRLF line terminators
 table ip x {
             ^^

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
6 months agosrc: rework singleton interval transformation to reduce memory consumption
Pablo Neira Ayuso [Fri, 3 Jan 2025 16:41:06 +0000 (17:41 +0100)] 
src: rework singleton interval transformation to reduce memory consumption

set_to_intervals() expands range expressions into a list of singleton
elements before building the netlink message that is sent to userspace.
This is because the kernel expects this list of singleton elements where
EXPR_F_INTERVAL_END denotes a closing interval. This expansion
significantly increases memory consumption in userspace.

This patch updates the logic to transform the range expression up to two
temporary singleton element expressions through setelem_to_interval().
Then, these two elements are used to allocate the nftnl_set_elem objects
through alloc_nftnl_setelem_interval() to build the netlink message,
finally all these temporary objects are released. For anonymous sets,
when adjacent ranges are found, the end element is not added to the set
to pack the set representation as in the original set_to_intervals()
routine.

After this update, set_to_intervals() only deals with adding the
non-matching all zero element to the interval set when it is not there
as the kernel expects.

In combination with the new EXPR_RANGE_VALUE expression, this shrinks
runtime userspace memory consumption from 70.50 Mbytes to 43.38 Mbytes
for a 100k intervals set sample.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
6 months agomnl: do not send set size when set is constant set
Pablo Neira Ayuso [Fri, 3 Jan 2025 16:41:01 +0000 (17:41 +0100)] 
mnl: do not send set size when set is constant set

When turning element range into the interval representation based on
singleton elements for the rbtree tree set backend, userspace adjusts
the size to the internal kernel implementation.

For constant sets, this is leaking an internal kernel implementation
detail that is fixed by kernel patch ("netfilter: nf_tables: fix set
size with rbtree backend"). For non-constant sets, set size is just
broken.

This patch is required by the follow up patch ("src: rework singleton
interval transformation to reduce memory consumption").

On top of this, constant sets cannot be updated once they are bound, set
size is not useful in this case. Remove this implicit set size for
constant sets.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
6 months agomnl: rename list of expression in mnl_nft_setelem_batch()
Pablo Neira Ayuso [Fri, 3 Jan 2025 16:40:58 +0000 (17:40 +0100)] 
mnl: rename list of expression in mnl_nft_setelem_batch()

Rename set to init to prepare to pass struct set to this function in
the follow up patch. No functional changes are intended.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
6 months agorule: constify set_is_non_concat_range()
Pablo Neira Ayuso [Fri, 3 Jan 2025 16:40:56 +0000 (17:40 +0100)] 
rule: constify set_is_non_concat_range()

This is read-only, constify it.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
6 months agosrc: add EXPR_RANGE_VALUE expression and use it
Pablo Neira Ayuso [Fri, 3 Jan 2025 16:40:54 +0000 (17:40 +0100)] 
src: add EXPR_RANGE_VALUE expression and use it

set element with range takes 4 instances of struct expr:

  EXPR_SET_ELEM -> EXPR_RANGE -> (2) EXPR_VALUE

where EXPR_RANGE represents two references to struct expr with constant
value.

This new EXPR_RANGE_VALUE trims it down to two expressions:

  EXPR_SET_ELEM -> EXPR_RANGE_VALUE

with two direct low and high values that represent the range:

  struct {
      mpz_t low;
      mpz_t high;
  };

this two new direct values in struct expr do not modify its size.

setelem_expr_to_range() translates EXPR_RANGE to EXPR_RANGE_VALUE, this
conversion happens at a later stage.

constant_range_expr_print() translates this structure to constant values
to reuse the existing datatype_print() which relies in singleton values.

The automerge routine has been updated to use EXPR_RANGE_VALUE.

This requires a follow up patch to rework the conversion from range
expression to singleton element to provide a noticeable memory
consumption reduction.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
6 months agointervals: do not merge intervals with different timeout
Pablo Neira Ayuso [Fri, 3 Jan 2025 16:40:52 +0000 (17:40 +0100)] 
intervals: do not merge intervals with different timeout

If timeout/expiration of contiguous intervals is different, then do not
merge them.

Fixes: 81e36530fcac ("src: replace interval segment tree overlap and automerge")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
6 months agointervals: add helper function to set previous element
Pablo Neira Ayuso [Fri, 3 Jan 2025 16:40:48 +0000 (17:40 +0100)] 
intervals: add helper function to set previous element

Add helper function to set previous element during the automerge
iteration. No functional changes are intended.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
6 months agorule: make cmd_free(NULL) valid
Florian Westphal [Wed, 8 Jan 2025 11:30:15 +0000 (12:30 +0100)] 
rule: make cmd_free(NULL) valid

bison uses cmd_free($$) as destructor, but base_cmd can
set it to NULL, e.g.

  |       ELEMENT         set_spec        set_block_expr
  {
    if (nft_cmd_collapse_elems(CMD_ADD, state->cmds, &$2, $3)) {
       handle_free(&$2);
       expr_free($3);
       $$ = NULL;   // cmd set to NULL
       break;
    }
    $$ = cmd_alloc(CMD_ADD, CMD_OBJ_ELEMENTS, &$2, &@$, $3);

expr_free(NULL) is legal, cmd_free() causes crash.  So just allow
this to avoid cluttering parser_bison.y with "if ($$)".

Also add the afl-generated bogon input to the test files.

Signed-off-by: Florian Westphal <fw@strlen.de>
Reviewed-by: Pablo Neira Ayuso <pablo@netfilter.org>
6 months agoparser_bison: fix UaF when reporting table parse error
Florian Westphal [Tue, 7 Jan 2025 22:55:06 +0000 (23:55 +0100)] 
parser_bison: fix UaF when reporting table parse error

It passed already-freed memory to erec function.  Found with afl++ and asan.

Fixes: 4955ae1a81b7 ("Add support for table's persist flag")
Signed-off-by: Florian Westphal <fw@strlen.de>
Reviewed-by: Pablo Neira Ayuso <pablo@netfilter.org>
6 months agotests: shell: add cgroupv2 socket match test case
Florian Westphal [Thu, 2 Jan 2025 17:08:30 +0000 (18:08 +0100)] 
tests: shell: add cgroupv2 socket match test case

This is a test case for nft_socket cgroupv2 matching, including
support for matching inside a cgroupv2 mount space added in kernel
commit 7f3287db6543 ("netfilter: nft_socket: make cgroupsv2 matching work with namespaces").

Test is thus run twice, once in the initial namespace and once with
a changed cgroupv2 root.

In case we can't create a cgroup or the 2nd half (unshared re-run)
fails, indicate SKIP.

Signed-off-by: Florian Westphal <fw@strlen.de>
6 months agomain: prepend error tag to printed errors when parsing options
Pablo Neira Ayuso [Tue, 17 Dec 2024 17:35:38 +0000 (18:35 +0100)] 
main: prepend error tag to printed errors when parsing options

Prepend "Error: " tag to printed errors in the option parsing step.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
6 months agolibnftables: include canonical path to avoid duplicates
Pablo Neira Ayuso [Thu, 12 Dec 2024 21:41:52 +0000 (22:41 +0100)] 
libnftables: include canonical path to avoid duplicates

A recent commit adds base directory of -f/--filename to include paths by
default to address a silly use of -I/--include to make this work:

  # nft -I /path/to -f /path/to/main.nft

instead users can simply invoke:

  # nft -f /path/to/main.nft

because /path/to/ is added at the end of the list of include paths.

This example above assumes main.nft includes more files that are
contained in /path/to/.

However, globbing can cause duplicates after this recent update, eg.

  # cat test/main
  table inet test {
        chain test {
                include "include/*";
        }
  }
  # nft -I /tmp/test/ -f test/main

because /tmp/test and test/ twice refer to the same directory and both
are added to the list of include path.

Use realpath() to canonicalize include paths. Then, search and skip
duplicated include paths.

Fixes: 302e9f8b3a13 ("libnftables: add base directory of -f/--filename to include path")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
6 months agosrc: shrink line_offset in struct location to 4 bytes
Pablo Neira Ayuso [Thu, 12 Dec 2024 23:06:14 +0000 (00:06 +0100)] 
src: shrink line_offset in struct location to 4 bytes

line_offset of 2^32 bytes should be enough.

This requires the removal of the last_line field (in a previous patch) to
shrink struct expr to 112 bytes.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
6 months agosrc: remove last_line from struct location
Pablo Neira Ayuso [Thu, 12 Dec 2024 23:04:40 +0000 (00:04 +0100)] 
src: remove last_line from struct location

This 4 bytes field is never used, remove it.

This does not shrink struct location in x86_64 due to alignment.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
6 months agosrc: remove unused token_offset from struct location
Pablo Neira Ayuso [Mon, 9 Dec 2024 00:23:08 +0000 (01:23 +0100)] 
src: remove unused token_offset from struct location

This saves 8 bytes in x86_64 in struct location which is embedded in
every expression.

This shrinks struct expr to 120 bytes according to pahole.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
6 months agoexpression: remove elem_flags from EXPR_SET_ELEM to shrink struct expr size
Pablo Neira Ayuso [Sun, 8 Dec 2024 20:46:13 +0000 (21:46 +0100)] 
expression: remove elem_flags from EXPR_SET_ELEM to shrink struct expr size

Move NFTNL_SET_ELEM_F_INTERVAL_OPEN flag to the existing flags field in
struct expr.

This saves 4 bytes in struct expr, shrinking it to 128 bytes according to
pahole. This reworks:

6089630f54ce ("segtree: Introduce flag for half-open range elements")

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
6 months agointervals: set internal element location with the deletion trigger
Pablo Neira Ayuso [Wed, 4 Dec 2024 22:36:05 +0000 (23:36 +0100)] 
intervals: set internal element location with the deletion trigger

set location of internal elements (already in the kernel) to the one
that partial or fully deletes it.

Otherwise, error reporting refers to internal location.

Before this patch:

 # nft delete element x y { 1.1.1.3 }
 Error: Could not process rule: Too many open files in system
 delete element x y { 1.1.1.3 }
                      ^^^^^^^

After this patch:

 # nft delete element x y { 1.1.1.3 }
 Error: Could not process rule: Too many open files in system
 delete element x y { 1.1.1.3 }
                      ^^^^^^^

This occurs after splitting an existing interval in two:

 remove: [1010100-10101ff]
 add: [1010100-1010102]
 add: [1010104-10101ff]

which results in two additions after removing the existing interval
that is split.

Fixes: 81e36530fcac ("src: replace interval segment tree overlap and automerge")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
6 months agotests: shell: add a test case for netdev ruleset flush + parallel link down
Florian Westphal [Sat, 7 Dec 2024 11:17:02 +0000 (12:17 +0100)] 
tests: shell: add a test case for netdev ruleset flush + parallel link down

Test for bug added with kernel commit
c03d278fdf35 ("netfilter: nf_tables: wait for rcu grace period on net_device removal")

Signed-off-by: Florian Westphal <fw@strlen.de>
7 months agosrc: allow binop expressions with variable right-hand operands
Jeremy Sowden [Mon, 18 Nov 2024 23:18:28 +0000 (00:18 +0100)] 
src: allow binop expressions with variable right-hand operands

Hitherto, the kernel has required constant values for the `xor` and
`mask` attributes of boolean bitwise expressions.  This has meant that
the right-hand operand of a boolean binop must be constant.  Now the
kernel has support for AND, OR and XOR operations with right-hand
operands passed via registers, we can relax this restriction.  Allow
non-constant right-hand operands if the left-hand operand is not
constant, e.g.:

  ct mark & 0xffff0000 | meta mark & 0xffff

The kernel now supports performing AND, OR and XOR operations directly,
on one register and an immediate value or on two registers, so we need
to be able to generate and parse bitwise boolean expressions of this
form.

If a boolean operation has a constant RHS, we continue to send a
mask-and-xor expression to the kernel.

Add tests for {ct,meta} mark with variable RHS operands.

JSON support is also included.

This requires Linux kernel >= 6.13-rc.

[ Originally posted as patch 1/8 and 6/8 which has been collapsed and
  simplified to focus on initial {ct,meta} mark support. Tests have
  been extracted from 8/8 including a tests/py fix to payload output
  due to incorrect output in original patchset. JSON support has been
  extracted from patch 7/8 --pablo]

Signed-off-by: Jeremy Sowden <jeremy@azazel.net>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
7 months agooptimize: compare expression length
Pablo Neira Ayuso [Mon, 18 Nov 2024 11:44:06 +0000 (12:44 +0100)] 
optimize: compare expression length

do not merge raw payload expressions with different length.

Other expression rely on key comparison which is assumed to have the
same length already.

Fixes: 60dcc01d6351 ("optimize: add __expr_cmp()")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
8 months agomnl: fix basehook comparison
Donald Yandt [Fri, 22 Nov 2024 22:04:49 +0000 (17:04 -0500)] 
mnl: fix basehook comparison

When comparing two hooks, if both device names are null,
the comparison should return true, as they are considered equal.

Fixes: b8872b83eb365 ("src: mnl: prepare for listing all device netdev device hooks")
Signed-off-by: Donald Yandt <donald.yandt@gmail.com>
Signed-off-by: Phil Sutter <phil@nwl.cc>
8 months agomnl: restore --debug=netlink output with chains
Pablo Neira Ayuso [Thu, 7 Nov 2024 08:00:55 +0000 (09:00 +0100)] 
mnl: restore --debug=netlink output with chains

table and chain name are not displayed with --debug=netlink:

 # nft --debug=netlink -f /tmp/x
 inet (null) (null) use 0
 ...

Similar to 79acbfdbe536 ("mnl: restore --debug=netlink output with sets").

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
8 months agosrc: allow to map key to nfqueue number
Florian Westphal [Fri, 25 Oct 2024 07:47:25 +0000 (09:47 +0200)] 
src: allow to map key to nfqueue number

Allow to specify a numeric queue id as part of a map.
The parser side is easy, but the reverse direction (listing) is not.

'queue' is a statement, it doesn't have an expression.

Add a generic 'queue_type' datatype as a shim to the real basetype with
constant expressions, this is used only for udata build/parse, it stores
the "key" (the parser token, here "queue") as udata in kernel and can
then restore the original key.

Add a dumpfile to validate parser & output.

JSON support is missing because JSON allow typeof only since quite
recently.

Joint work with Pablo.

Closes: https://bugzilla.netfilter.org/show_bug.cgi?id=1455
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
8 months agodatatype: remove unused flags field
Pablo Neira Ayuso [Wed, 6 Nov 2024 22:31:06 +0000 (23:31 +0100)] 
datatype: remove unused flags field

Leftover unused struct datatype field, remove it.

Fixes: e35aabd511c4 ("datatype: replace DTYPE_F_ALLOC by bitfield")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
8 months agotests: monitor: Become $PWD agnostic
Phil Sutter [Thu, 7 Nov 2024 13:39:51 +0000 (14:39 +0100)] 
tests: monitor: Become $PWD agnostic

The call to 'cd' is problematic since later the script tries to 'exec
unshare -n $0'. This is not the only problem though: Individual test
cases specified on command line are expected to be relative to the
script's directory, too. Just get rid of these nonsensical restrictions.

Reported-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Phil Sutter <phil@nwl.cc>
8 months agotests: monitor: Run in own netns
Phil Sutter [Wed, 2 Oct 2024 16:17:07 +0000 (18:17 +0200)] 
tests: monitor: Run in own netns

Have the script call itself prefixed by unshare. This won't prevent
clashing test case contents, but at least leave the host netns alone.

Signed-off-by: Phil Sutter <phil@nwl.cc>
8 months agomonitor: Recognize flowtable add/del events
Phil Sutter [Wed, 15 May 2024 14:01:20 +0000 (16:01 +0200)] 
monitor: Recognize flowtable add/del events

These were entirely ignored before, add the necessary code analogous to
e.g. objects.

Signed-off-by: Phil Sutter <phil@nwl.cc>
8 months agotests: py: Fix for storing payload into missing file
Phil Sutter [Wed, 2 Oct 2024 17:55:49 +0000 (19:55 +0200)] 
tests: py: Fix for storing payload into missing file

When running a test for which no corresponding *.payload file exists,
the *.payload.got file name was incorrectly constructed due to
'payload_path' variable not being set.

Fixes: 2cfab7a3e10fc ("tests/py: Write dissenting payload into the right file")
Signed-off-by: Phil Sutter <phil@nwl.cc>
8 months agojson: Support typeof in set and map types
Phil Sutter [Fri, 27 Sep 2024 22:55:34 +0000 (00:55 +0200)] 
json: Support typeof in set and map types

Implement this as a special "type" property value which is an object
with sole property "typeof". The latter's value is the JSON
representation of the expression in set->key, so for concatenated
typeofs it is a concat expression.

All this is a bit clumsy right now but it works and it should be
possible to tear it down a bit for more user-friendliness in a
compatible way by either replacing the concat expression by the array it
contains or even the whole "typeof" object - the parser would just
assume any object (or objects in an array) in the "type" property value
are expressions to extract a type from.

Signed-off-by: Phil Sutter <phil@nwl.cc>
8 months agojson: collapse set element commands from parser
Pablo Neira Ayuso [Thu, 31 Oct 2024 20:38:02 +0000 (21:38 +0100)] 
json: collapse set element commands from parser

Update json parser to collapse {add,create} element commands to reduce
memory consumption in the case of large sets defined by one element per
command:

{"nftables": [{"add": {"element": {"family": "ip", "table": "x", "name":
"y", "elem": [{"set": ["1.1.0.0"]}]}}},...]}

Add CTX_F_COLLAPSED flag to report that command has been collapsed.

This patch reduces memory consumption by ~32% this case.

Fixes: 20f1c60ac8c8 ("src: collapse set element commands from parser")
Reported-by: Eric Garver <eric@garver.life>
Tested-by: Eric Garver <eric@garver.life>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
8 months agotests: shell: move device to different namespace
Pablo Neira Ayuso [Mon, 28 Oct 2024 22:17:14 +0000 (23:17 +0100)] 
tests: shell: move device to different namespace

This actually triggers a UNREGISTER event, it is similar to existing
tests, but add this test to improve coverage for this scenario.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
9 months agodoc: extend description of fib expression
Florian Westphal [Thu, 10 Oct 2024 13:37:42 +0000 (15:37 +0200)] 
doc: extend description of fib expression

Describe the input keys and the result types.
Mention which input keys are mandatory and which keys are mutually
exclusive.

Describe which hooks can be used with the various lookup modifiers
and extend the examples with more information on fib expression
capabilities.

Closes: https://bugzilla.netfilter.org/show_bug.cgi?id=1663
Signed-off-by: Florian Westphal <fw@strlen.de>
Reviewed-by: Pablo Neira Ayuso <pablo@netfilter.org>
9 months agotests: monitor: fix up test case breakage
Florian Westphal [Tue, 29 Oct 2024 20:12:19 +0000 (21:12 +0100)] 
tests: monitor: fix up test case breakage

Monitor test fails:

 echo: running tests from file set-simple.t
 echo output differs!
  -add element ip t portrange { 1024-65535 }
   add element ip t portrange { 100-200 }
  +add element ip t portrange { 1024-65535 }
  +# new generation 510 by process 129009 (nft)

I also noticed -j mode did not work correctly, add missing json annotations
in set-concat-interval.t while at it.

Signed-off-by: Florian Westphal <fw@strlen.de>
9 months agotests: shell: don't rely on writable test directory
Florian Westphal [Tue, 22 Oct 2024 13:26:54 +0000 (15:26 +0200)] 
tests: shell: don't rely on writable test directory

Running shell tests from a virtme-ng instance with ro mapped test dir
hangs due to runaway 'awk' reading from stdin instead of the intended
$tmpfile (variable is empty), so add quotes where needed.

0002relative_0 wants to check relative includes. It tries to create a
temporary file in the current directory, which fails as thats readonly
inside the virtme vm instance.

[ -w ! $foo ... did not catch this due to missing "".
Add quotes and return the skip retval so the test gets flagged as skipped.

0013input_descriptors_included_files_0 and 0020include_chain_0 are
switched to normal tmpfiles, there is nothing in the test that needs
relative includes.

Also, get rid of some error tests for subsequent mktemp calls for
scripts that already called 'set -e'.

Signed-off-by: Florian Westphal <fw@strlen.de>
9 months agosrc: fix extended netlink error reporting with large set elements
Pablo Neira Ayuso [Wed, 23 Oct 2024 22:24:55 +0000 (00:24 +0200)] 
src: fix extended netlink error reporting with large set elements

Large sets can expand into several netlink messages, use sequence number
and attribute offset to correlate the set element and the location.

When set element command expands into several netlink messages,
increment sequence number for each netlink message. Update struct cmd to
store the range of netlink messages that result from this command.

struct nlerr_loc remains in the same size in x86_64.

 # nft -f set-65535.nft
 set-65535.nft:65029:22-32: Error: Could not process rule: File exists
 create element x y { 1.1.254.253 }
                      ^^^^^^^^^^^

Fixes: f8aec603aa7e ("src: initial extended netlink error reporting")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
9 months agorule: netlink attribute offset is uint32_t for struct nlerr_loc
Pablo Neira Ayuso [Wed, 23 Oct 2024 22:08:24 +0000 (00:08 +0200)] 
rule: netlink attribute offset is uint32_t for struct nlerr_loc

The maximum netlink message length (nlh->nlmsg_len) is uint32_t, struct
nlerr_loc stores the offset to the netlink attribute which must be
uint32_t, not uint16_t.

While at it, remove check for zero netlink attribute offset in
nft_cmd_error() which should not ever happen, likely this check was
there to prevent the uint16_t offset overflow.

Fixes: f8aec603aa7e ("src: initial extended netlink error reporting")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
9 months agomnl: update cmd_add_loc() to take struct nlmsghdr
Pablo Neira Ayuso [Wed, 23 Oct 2024 21:07:31 +0000 (23:07 +0200)] 
mnl: update cmd_add_loc() to take struct nlmsghdr

To prepare for a fix for very large sets.

No functional change is intended.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
9 months agomnl: rename to mnl_seqnum_alloc() to mnl_seqnum_inc()
Pablo Neira Ayuso [Wed, 23 Oct 2024 20:15:24 +0000 (22:15 +0200)] 
mnl: rename to mnl_seqnum_alloc() to mnl_seqnum_inc()

rename mnl_seqnum_alloc() to mnl_seqnum_inc().

No functional change is intended.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
9 months agosrc: collapse set element commands from parser
Pablo Neira Ayuso [Wed, 23 Oct 2024 09:43:58 +0000 (11:43 +0200)] 
src: collapse set element commands from parser

498a5f0c219d ("rule: collapse set element commands") does not help to
reduce memory consumption in the case of large sets defined by one
element per line:

 add element ip x y { 1.1.1.1 }
 add element ip x y { 1.1.1.2 }
 ...

This patch reduces memory consumption by ~75%, set elements are
collapsed into an existing cmd object wherever possible to reduce the
number of cmd objects.

This patch also adds a special case for variables for sets similar to:

  be055af5c58d ("cmd: skip variable set elements when collapsing commands")

This patch requires this small kernel fix:

 commit b53c116642502b0c85ecef78bff4f826a7dd4145
 Author: Pablo Neira Ayuso <pablo@netfilter.org>
 Date:   Fri May 20 00:02:06 2022 +0200

    netfilter: nf_tables: set element extended ACK reporting support

which is already included in recent -stable kernels:

 # cat ruleset.nft
 add table ip x
 add chain ip x y
 add set ip x y { type ipv4_addr; }
 create element ip x y { 1.1.1.1 }
 create element ip x y { 1.1.1.1 }

 # nft -f ruleset.nft
 ruleset.nft:5:25-31: Error: Could not process rule: File exists
 create element ip x y { 1.1.1.1 }
                         ^^^^^^^

since there is no need to relate commands via sequence number anymore,
this allows also removes the uncollapse step.

Fixes: 498a5f0c219d ("rule: collapse set element commands")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
9 months agolibnftables-json: fix raw payload expression documentation
Eric Long [Thu, 17 Oct 2024 15:33:17 +0000 (23:33 +0800)] 
libnftables-json: fix raw payload expression documentation

Raw payload expression accesses payload data in bits, not bytes.

Fixes: 872f373dc50f7 ("doc: Add JSON schema documentation")
Signed-off-by: Eric Long <i@hack3r.moe>
Signed-off-by: Phil Sutter <phil@nwl.cc>
9 months agotests: shell: Join arithmetic statements in maps/vmap_timeout
Phil Sutter [Fri, 11 Oct 2024 09:22:44 +0000 (11:22 +0200)] 
tests: shell: Join arithmetic statements in maps/vmap_timeout

In light of the recent typo fix, go an extra step and merge the modulo
and offset adjustment in a single term.

Signed-off-by: Phil Sutter <phil@nwl.cc>
9 months agotests: shell: fix spurious dump failure in vmap timeout test
Florian Westphal [Fri, 11 Oct 2024 00:32:08 +0000 (02:32 +0200)] 
tests: shell: fix spurious dump failure in vmap timeout test

Blamed commit can update the timeout to 6s, but last line waits
for 5 seconds and expects that to be enough to have all elements vanish.

Fix the typo to limit update timeout also to 5 seconds and not 6.
This fixes spurious dump failures like this one:

-               elements = { 1.2.3.4 . 22 : jump ssh_input }
+               elements = { 1.2.3.4 . 22 : jump ssh_input,
+                            10.0.95.144 . 38023 timeout 6s expires 545ms : jump other_input }

Fixes: db80037c0279 ("tests: shell: extend vmap test with updates")
Signed-off-by: Florian Westphal <fw@strlen.de>
9 months agobuild: Bump version to 1.1.1 v1.1.1
Pablo Neira Ayuso [Wed, 2 Oct 2024 20:45:45 +0000 (22:45 +0200)] 
build: Bump version to 1.1.1

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
10 months agocache: initialize filter when fetching implicit chains
Pablo Neira Ayuso [Tue, 17 Sep 2024 17:18:09 +0000 (19:18 +0200)] 
cache: initialize filter when fetching implicit chains

ASAN reports:

  src/cache.c:734:25: runtime error: load of value 189, which is not a valid value for type '_Bool'

because filter->reset.rule remains uninitialized.

Initialize filter and replace existing construct to initialize table and
chain which leaves remaining fields uninitialized.

Fixes: dbff26bfba83 ("cache: consolidate reset command")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
10 months agodoc: tproxy is non-terminal in nftables
Pablo Neira Ayuso [Sun, 15 Sep 2024 22:34:27 +0000 (00:34 +0200)] 
doc: tproxy is non-terminal in nftables

iptables TPROXY issues NF_ACCEPT while nftables tproxy allows for
post-processing. Update examples. For more info, see:

https://lore.kernel.org/netfilter-devel/ZuSh_Io3Yt8LkyUh@orbyte.nwl.cc/T/

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
10 months agosrc: support for timeout never in elements
Pablo Neira Ayuso [Mon, 2 Sep 2024 23:32:05 +0000 (01:32 +0200)] 
src: support for timeout never in elements

Allow to specify elements that never expire in sets with global
timeout.

    set x {
        typeof ip saddr
        timeout 1m
        elements = { 1.1.1.1 timeout never,
                     2.2.2.2,
                     3.3.3.3 timeout 2m }
    }

in this example above:

 - 1.1.1.1 is a permanent element
 - 2.2.2.2 expires after 1 minute (uses default set timeout)
 - 3.3.3.3 expires after 2 minutes (uses specified timeout override)

Use internal NFT_NEVER_TIMEOUT marker as UINT64_MAX to differenciate
between use default set timeout and timeout never if "timeout N" is used
in set declaration. Maximum supported timeout in milliseconds which is
conveyed within a netlink attribute is 0x10c6f7a0b5ec.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
10 months agotests: shell: more randomization for timeout parameter
Florian Westphal [Sat, 14 Sep 2024 21:56:14 +0000 (23:56 +0200)] 
tests: shell: more randomization for timeout parameter

Either pass no timeout argument, pass timeout+expires or omit
timeout (uses default timeout, if any).

This should not expose further kernel code to run at this time, but unlike
the existing (deterministic) element-update test case this script does
have live traffic and different set types, including rhashtable which has
async gc.

Signed-off-by: Florian Westphal <fw@strlen.de>
10 months agotests: py: fix up udp csum fixup output
Florian Westphal [Wed, 11 Sep 2024 12:23:01 +0000 (14:23 +0200)] 
tests: py: fix up udp csum fixup output

Preceeding commit switched udp to use the inkernel csum parser, so tests
warn:

WARNING: line 7: 'add rule ip test-ip4 input iif "lo" udp checksum set 0':
'[ payload write reg 1 => 2b @ transport header + 6 csum_type 1 csum_off 6 csum_flags 0x0 ]' mismatches
'[ payload write reg 1 => 2b @ transport header + 6 csum_type 0 csum_off 0 csum_flags 0x1 ]'

Fixes: f89abfb4068d ("proto: use NFT_PAYLOAD_L4CSUM_PSEUDOHDR flag to mangle UDP checksum")
Signed-off-by: Florian Westphal <fw@strlen.de>
10 months agoproto: use NFT_PAYLOAD_L4CSUM_PSEUDOHDR flag to mangle UDP checksum
Pablo Neira Ayuso [Mon, 9 Sep 2024 10:48:33 +0000 (12:48 +0200)] 
proto: use NFT_PAYLOAD_L4CSUM_PSEUDOHDR flag to mangle UDP checksum

There are two mechanisms to update the UDP checksum field:

 1) _CSUM_TYPE and _CSUM_OFFSET which specify the type of checksum
    (e.g. inet) and offset where it is located.
 2) use NFT_PAYLOAD_L4CSUM_PSEUDOHDR flag to use layer 4 kernel
    protocol parser.

The problem with 1) is that it is inconditional, that is, csum_type and
csum_offset cannot deal with zero UDP checksum.

Use NFT_PAYLOAD_L4CSUM_PSEUDOHDR flag instead since it relies on the
layer 4 kernel parser which skips updating zero UDP checksum.

Extend test coverage for the UDP mangling with and without zero
checksum.

Fixes: e6c9174e13b2 ("proto: add checksum key information to struct proto_desc")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
10 months agotests: shell: stabilize packetpath/payload
Pablo Neira Ayuso [Mon, 9 Sep 2024 10:47:35 +0000 (12:47 +0200)] 
tests: shell: stabilize packetpath/payload

- Add sleep calls after setting up container topology.
- Extend TCP connect timeout to 4 seconds. Test has no listener, this is
  just sending SYN packets that are rejected but it works to test the
  payload mangling ruleset.
- fix incorrect logic to check for 0 matching packets through grep.

Fixes: 84da729e067a ("tests: shell: add test to cover payload transport match and mangle")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
10 months agotests: shell: add test case for timeout updates
Florian Westphal [Mon, 9 Sep 2024 15:26:01 +0000 (17:26 +0200)] 
tests: shell: add test case for timeout updates

Needs a feature check file, so add one:
Add element with 1m timeout, then update expiry to 1ms.
If element still exists after 1ms, update request was ignored.

Test case checks timeouts can both be incremented and decremented,
checks error recovery (update request but transaction fails) and
that expiry is restored in addion to timeout.

Signed-off-by: Florian Westphal <fw@strlen.de>
10 months agotests: shell: extend vmap test with updates
Florian Westphal [Mon, 9 Sep 2024 15:13:46 +0000 (17:13 +0200)] 
tests: shell: extend vmap test with updates

It won't validate that the update is actually effective,
but it will trigger relevant update logic in kernel.

This means the updated test works even if the kernel doesn't
support updates.

A dedicated test will be added to check timeout updates work.

Signed-off-by: Florian Westphal <fw@strlen.de>
10 months agotests: shell: add test for kernel stack recursion bug
Florian Westphal [Tue, 10 Sep 2024 09:47:44 +0000 (11:47 +0200)] 
tests: shell: add test for kernel stack recursion bug

Validate that such ruleset updates get rejected.

Signed-off-by: Florian Westphal <fw@strlen.de>
10 months agolibnftables: Zero ctx->vars after freeing it
Phil Sutter [Tue, 3 Sep 2024 15:43:19 +0000 (17:43 +0200)] 
libnftables: Zero ctx->vars after freeing it

Leaving the invalid pointer value in place will cause a double-free when
users call nft_ctx_clear_vars() first, then nft_ctx_free(). Moreover,
nft_ctx_add_var() passes the pointer to mrealloc() and thus assumes it
to be either NULL or valid.

Closes: https://bugzilla.netfilter.org/show_bug.cgi?id=1772
Fixes: 9edaa6a51eab4 ("src: add --define key=value")
Signed-off-by: Phil Sutter <phil@nwl.cc>
10 months agotests: shell: extend coverage for meta l4proto netdev/egress matching
Pablo Neira Ayuso [Thu, 29 Aug 2024 10:42:05 +0000 (12:42 +0200)] 
tests: shell: extend coverage for meta l4proto netdev/egress matching

Extend coverage to match on small UDP packets from netdev/egress.

While at it, cover bridge/input and bridge/output hooks too.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
11 months agocache: position does not require full cache
Pablo Neira Ayuso [Thu, 29 Aug 2024 10:42:17 +0000 (12:42 +0200)] 
cache: position does not require full cache

position refers to the rule handle, it has similar cache requirements as
replace rule command, relax cache requirements.

Commit e5382c0d08e3 ("src: Support intra-transaction rule references")
uses position.id for index support which requires a full cache, but
only in such case.

Fixes: 01e5c6f0ed03 ("src: add cache level flags")
Tested-by: Eric Garver <eric@garver.life>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
11 months agocache: relax requirement for replace rule command
Pablo Neira Ayuso [Thu, 29 Aug 2024 10:42:14 +0000 (12:42 +0200)] 
cache: relax requirement for replace rule command

No need for full cache, this command relies on the rule handle which is
not validated from userspace. Cache requirements are similar to those
of add/create/delete rule commands.

This speeds up incremental updates with large rulesets.

Extend tests/coverage for rule replacement.

Fixes: 01e5c6f0ed03 ("src: add cache level flags")
Tested-by: Eric Garver <eric@garver.life>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
11 months agocache: remove full cache requirement when echo flag is set on
Pablo Neira Ayuso [Thu, 29 Aug 2024 10:42:12 +0000 (12:42 +0200)] 
cache: remove full cache requirement when echo flag is set on

The echo flag does not use the cache infrastructure yet, it relies on
the monitor cache which follows the netlink_echo_callback() path.

Fixes: 01e5c6f0ed03 ("src: add cache level flags")
Tested-by: Eric Garver <eric@garver.life>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
11 months agocache: clean up evaluate_cache_del()
Pablo Neira Ayuso [Thu, 29 Aug 2024 10:42:10 +0000 (12:42 +0200)] 
cache: clean up evaluate_cache_del()

Move NFT_CACHE_TABLE flag to default case to disentangle this.

Tested-by: Eric Garver <eric@garver.life>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
11 months agocache: assert filter when calling nft_cache_evaluate()
Pablo Neira Ayuso [Thu, 29 Aug 2024 10:42:08 +0000 (12:42 +0200)] 
cache: assert filter when calling nft_cache_evaluate()

nft_cache_evaluate() always takes a non-null filter, remove superfluous
checks when calculating cache requirements via flags.

Note that filter is still option from netlink dump path, since this can
be called from error path to provide hints.

Fixes: 08725a9dc14c ("cache: filter out rules by chain")
Fixes: b3ed8fd8c9f3 ("cache: missing family in cache filtering")
Fixes: 635ee1cad8aa ("cache: filter out sets and maps that are not requested")
Fixes: 3f1d3912c3a6 ("cache: filter out tables that are not requested")
Tested-by: Eric Garver <eric@garver.life>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
11 months agotests: shell: cover reset command with counter and quota
Pablo Neira Ayuso [Sun, 25 Aug 2024 22:41:45 +0000 (00:41 +0200)] 
tests: shell: cover reset command with counter and quota

Tested-by: Eric Garver <eric@garver.life>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
11 months agotests: shell: cover anonymous set with reset command
Pablo Neira Ayuso [Sun, 25 Aug 2024 22:41:43 +0000 (00:41 +0200)] 
tests: shell: cover anonymous set with reset command

Extend existing test to reset counters for rules with anonymous set.

Closes: https://bugzilla.netfilter.org/show_bug.cgi?id=1763
Tested-by: Eric Garver <eric@garver.life>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>