]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
src: support for timeout never in elements
authorPablo Neira Ayuso <pablo@netfilter.org>
Mon, 2 Sep 2024 23:32:05 +0000 (01:32 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Tue, 17 Sep 2024 19:26:50 +0000 (21:26 +0200)
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>
include/nftables.h
src/expression.c
src/netlink.c
src/parser_bison.y

index 4b7c335928dadc18a96921453fc53c3f3d3128c4..c25deb3676ddbd9d10e3ad707a85515a20aface6 100644 (file)
@@ -241,4 +241,7 @@ int nft_optimize(struct nft_ctx *nft, struct list_head *cmds);
 
 #define __NFT_OUTPUT_NOTSUPP   UINT_MAX
 
+/* internal marker, not used by the kernel. */
+#define NFT_NEVER_TIMEOUT      UINT64_MAX
+
 #endif /* NFTABLES_NFTABLES_H */
index 992f5106405129721443e224b75e4558c69d3ef4..c0cb7f22eb73dcb5c4dea2d727964fbc02ad9343 100644 (file)
@@ -1314,9 +1314,14 @@ static void set_elem_expr_print(const struct expr *expr,
        }
        if (expr->timeout) {
                nft_print(octx, " timeout ");
-               time_print(expr->timeout, octx);
+               if (expr->timeout == NFT_NEVER_TIMEOUT)
+                       nft_print(octx, "never");
+               else
+                       time_print(expr->timeout, octx);
        }
-       if (!nft_output_stateless(octx) && expr->expiration) {
+       if (!nft_output_stateless(octx) &&
+           expr->timeout != NFT_NEVER_TIMEOUT &&
+           expr->expiration) {
                nft_print(octx, " expires ");
                time_print(expr->expiration, octx);
        }
index dea95ffa0704abcb4783166454044fe0449b3c4b..25ee3419772b305137d971fe22d59b03916efbbe 100644 (file)
@@ -155,9 +155,14 @@ struct nftnl_set_elem *alloc_nftnl_setelem(const struct expr *set,
                break;
        }
 
-       if (elem->timeout)
-               nftnl_set_elem_set_u64(nlse, NFTNL_SET_ELEM_TIMEOUT,
-                                      elem->timeout);
+       if (elem->timeout) {
+               uint64_t timeout = elem->timeout;
+
+               if (elem->timeout == NFT_NEVER_TIMEOUT)
+                       timeout = 0;
+
+               nftnl_set_elem_set_u64(nlse, NFTNL_SET_ELEM_TIMEOUT, timeout);
+       }
        if (elem->expiration)
                nftnl_set_elem_set_u64(nlse, NFTNL_SET_ELEM_EXPIRATION,
                                       elem->expiration);
@@ -1417,8 +1422,12 @@ key_end:
        expr = set_elem_expr_alloc(&netlink_location, key);
        expr->flags |= EXPR_F_KERNEL;
 
-       if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_TIMEOUT))
+       if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_TIMEOUT)) {
                expr->timeout    = nftnl_set_elem_get_u64(nlse, NFTNL_SET_ELEM_TIMEOUT);
+               if (expr->timeout == 0)
+                       expr->timeout    = NFT_NEVER_TIMEOUT;
+       }
+
        if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_EXPIRATION))
                expr->expiration = nftnl_set_elem_get_u64(nlse, NFTNL_SET_ELEM_EXPIRATION);
        if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_USERDATA))
index 8fbb98bdcd694b177804aa01a0e0e26bcc06a7ec..e2936d10efe4c7ae7670aee0420eddb095fe2bd4 100644 (file)
@@ -695,7 +695,7 @@ int nft_lex(void *, void *, void *);
 %type <string>                 identifier type_identifier string comment_spec
 %destructor { free_const($$); }        identifier type_identifier string comment_spec
 
-%type <val>                    time_spec time_spec_or_num_s quota_used
+%type <val>                    time_spec time_spec_or_num_s set_elem_time_spec quota_used
 
 %type <expr>                   data_type_expr data_type_atom_expr
 %destructor { expr_free($$); }  data_type_expr data_type_atom_expr
@@ -4545,7 +4545,28 @@ set_elem_options :       set_elem_option
                        |       set_elem_options        set_elem_option
                        ;
 
-set_elem_option                :       TIMEOUT                 time_spec
+set_elem_time_spec     :       STRING
+                       {
+                               struct error_record *erec;
+                               uint64_t res;
+
+                               if (!strcmp("never", $1)) {
+                                       free_const($1);
+                                       $$ = NFT_NEVER_TIMEOUT;
+                                       break;
+                               }
+
+                               erec = time_parse(&@1, $1, &res);
+                               free_const($1);
+                               if (erec != NULL) {
+                                       erec_queue(erec, state->msgs);
+                                       YYERROR;
+                               }
+                               $$ = res;
+                       }
+                       ;
+
+set_elem_option                :       TIMEOUT         time_spec
                        {
                                $<expr>0->timeout = $2;
                        }
@@ -4655,7 +4676,7 @@ set_elem_stmt             :       COUNTER close_scope_counter
                        }
                        ;
 
-set_elem_expr_option   :       TIMEOUT                 time_spec
+set_elem_expr_option   :       TIMEOUT         set_elem_time_spec
                        {
                                $<expr>0->timeout = $2;
                        }