]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
table: Embed creating nft version into userdata
authorPhil Sutter <phil@nwl.cc>
Mon, 12 May 2025 20:59:26 +0000 (22:59 +0200)
committerPhil Sutter <phil@nwl.cc>
Thu, 28 Aug 2025 10:47:15 +0000 (12:47 +0200)
Upon listing a table which was created by a newer version of nftables,
warn about the potentially incomplete content.

Suggested-by: Florian Westphal <fw@strlen.de>
Cc: Dan Winship <danwinship@redhat.com>
Signed-off-by: Phil Sutter <phil@nwl.cc>
Acked-by: Pablo Neira Ayuso <pablo@netfilter.org>
.gitignore
Makefile.am
configure.ac
include/rule.h
src/mnl.c
src/netlink.c
src/rule.c

index a62e31f31c6b5d549553dd061e4577008044810a..1e3bc5146b2f1de689038c9ca706cf86266ba8b6 100644 (file)
@@ -14,6 +14,7 @@ autom4te.cache
 build-aux/
 libnftables.pc
 libtool
+nftversion.h
 
 # cscope files
 /cscope.*
index 51dadbe64649e3dd9c5364a50b187c936698df84..5190a49ae69f13739d4f6761a53e0f1df57b2f5b 100644 (file)
@@ -33,6 +33,7 @@ sbin_PROGRAMS =
 check_PROGRAMS =
 dist_man_MANS =
 CLEANFILES =
+DISTCLEANFILES =
 
 ###############################################################################
 
@@ -107,6 +108,8 @@ noinst_HEADERS = \
        \
        $(NULL)
 
+DISTCLEANFILES += nftversion.h
+
 ###############################################################################
 
 AM_CPPFLAGS = \
index 3a751cb054b9ff6b0356572bffee5a8e473bfc01..da16a6e257c911a9f039609cf67559c00b7c12e7 100644 (file)
@@ -131,6 +131,30 @@ AC_ARG_WITH([unitdir],
 )
 AC_SUBST([unitdir])
 
+AC_ARG_WITH([stable-release], [AS_HELP_STRING([--with-stable-release],
+            [Stable release number])],
+            [], [with_stable_release=0])
+AC_CONFIG_COMMANDS([stable_release],
+                   [STABLE_RELEASE=$stable_release],
+                   [stable_release=$with_stable_release])
+AC_CONFIG_COMMANDS([nftversion.h], [
+(
+       echo "static char nftversion[[]] = {"
+       echo "  ${VERSION}," | tr '.' ','
+       echo "  ${STABLE_RELEASE}"
+       echo "};"
+       echo "static char nftbuildstamp[[]] = {"
+       for ((i = 56; i >= 0; i-= 8)); do
+               echo "  ((uint64_t)MAKE_STAMP >> $i) & 0xff,"
+       done
+       echo "};"
+) >nftversion.h
+])
+# Current date should be fetched exactly once per build,
+# so have 'make' call date and pass the value to every 'gcc' call
+AC_SUBST([MAKE_STAMP], ["\$(shell date +%s)"])
+CFLAGS="${CFLAGS} -DMAKE_STAMP=\${MAKE_STAMP}"
+
 AC_CONFIG_FILES([                                      \
                Makefile                                \
                libnftables.pc                          \
index 498a88bf63a66dd6fc0d509535d41debd09835b0..8d2f29d09337e52aa8976004a0098ea15baa348b 100644 (file)
@@ -170,6 +170,7 @@ struct table {
        uint32_t                owner;
        const char              *comment;
        bool                    has_xt_stmts;
+       bool                    is_from_future;
 };
 
 extern struct table *table_alloc(void);
index 273cefe84e833b90efc75edd5d411c23f7ab9d2f..984dcac27b1cfdad9733710a8afc14a0d768433e 100644 (file)
--- a/src/mnl.c
+++ b/src/mnl.c
@@ -10,6 +10,7 @@
 
 #include <nft.h>
 #include <iface.h>
+#include <nftversion.h>
 
 #include <libmnl/libmnl.h>
 #include <libnftnl/common.h>
@@ -1082,24 +1083,32 @@ int mnl_nft_table_add(struct netlink_ctx *ctx, struct cmd *cmd,
        if (nlt == NULL)
                memory_allocation_error();
 
+       udbuf = nftnl_udata_buf_alloc(NFT_USERDATA_MAXLEN);
+       if (!udbuf)
+               memory_allocation_error();
+
        nftnl_table_set_u32(nlt, NFTNL_TABLE_FAMILY, cmd->handle.family);
        if (cmd->table) {
                nftnl_table_set_u32(nlt, NFTNL_TABLE_FLAGS, cmd->table->flags);
 
                if (cmd->table->comment) {
-                       udbuf = nftnl_udata_buf_alloc(NFT_USERDATA_MAXLEN);
-                       if (!udbuf)
-                               memory_allocation_error();
                        if (!nftnl_udata_put_strz(udbuf, NFTNL_UDATA_TABLE_COMMENT, cmd->table->comment))
                                memory_allocation_error();
-                       nftnl_table_set_data(nlt, NFTNL_TABLE_USERDATA, nftnl_udata_buf_data(udbuf),
-                                            nftnl_udata_buf_len(udbuf));
-                       nftnl_udata_buf_free(udbuf);
                }
        } else {
                nftnl_table_set_u32(nlt, NFTNL_TABLE_FLAGS, 0);
        }
 
+       if (!nftnl_udata_put(udbuf, NFTNL_UDATA_TABLE_NFTVER,
+                            sizeof(nftversion), nftversion) ||
+           !nftnl_udata_put(udbuf, NFTNL_UDATA_TABLE_NFTBLD,
+                            sizeof(nftbuildstamp), nftbuildstamp))
+               memory_allocation_error();
+       nftnl_table_set_data(nlt, NFTNL_TABLE_USERDATA,
+                            nftnl_udata_buf_data(udbuf),
+                            nftnl_udata_buf_len(udbuf));
+       nftnl_udata_buf_free(udbuf);
+
        nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(ctx->batch),
                                    NFT_MSG_NEWTABLE,
                                    cmd->handle.family,
index 5876c08929f7ac5cb4aa08872eef7d985a1c6081..5511d9888e5bd578bf0086eff15a532a30b0c71b 100644 (file)
@@ -10,6 +10,7 @@
  */
 
 #include <nft.h>
+#include <nftversion.h>
 
 #include <errno.h>
 #include <libmnl/libmnl.h>
@@ -799,6 +800,14 @@ static int table_parse_udata_cb(const struct nftnl_udata *attr, void *data)
                        if (value[len - 1] != '\0')
                                return -1;
                        break;
+               case NFTNL_UDATA_TABLE_NFTVER:
+                       if (len != sizeof(nftversion))
+                               return -1;
+                       break;
+               case NFTNL_UDATA_TABLE_NFTBLD:
+                       if (len != sizeof(nftbuildstamp))
+                               return -1;
+                       break;
                default:
                        return 0;
        }
@@ -806,6 +815,29 @@ static int table_parse_udata_cb(const struct nftnl_udata *attr, void *data)
        return 0;
 }
 
+static int version_cmp(const struct nftnl_udata **ud)
+{
+       const char *udbuf;
+       size_t i;
+
+       /* netlink attribute lengths checked by table_parse_udata_cb() */
+       if (ud[NFTNL_UDATA_TABLE_NFTVER]) {
+               udbuf = nftnl_udata_get(ud[NFTNL_UDATA_TABLE_NFTVER]);
+               for (i = 0; i < sizeof(nftversion); i++) {
+                       if (nftversion[i] != udbuf[i])
+                               return nftversion[i] - udbuf[i];
+               }
+       }
+       if (ud[NFTNL_UDATA_TABLE_NFTBLD]) {
+               udbuf = nftnl_udata_get(ud[NFTNL_UDATA_TABLE_NFTBLD]);
+               for (i = 0; i < sizeof(nftbuildstamp); i++) {
+                       if (nftbuildstamp[i] != udbuf[i])
+                               return nftbuildstamp[i] - udbuf[i];
+               }
+       }
+       return 0;
+}
+
 struct table *netlink_delinearize_table(struct netlink_ctx *ctx,
                                        const struct nftnl_table *nlt)
 {
@@ -830,6 +862,7 @@ struct table *netlink_delinearize_table(struct netlink_ctx *ctx,
                }
                if (ud[NFTNL_UDATA_TABLE_COMMENT])
                        table->comment = xstrdup(nftnl_udata_get(ud[NFTNL_UDATA_TABLE_COMMENT]));
+               table->is_from_future = version_cmp(ud) < 0;
        }
 
        return table;
index e6216bcabf4072f351fbac9ebfe73aeca66da48e..ceb56488d37f6734b78b5c298e71eac68a3930ea 100644 (file)
@@ -1298,6 +1298,10 @@ static void table_print(const struct table *table, struct output_ctx *octx)
                fprintf(octx->error_fp,
                        "# Warning: table %s %s is managed by iptables-nft, do not touch!\n",
                        family, table->handle.table.name);
+       if (table->is_from_future)
+               fprintf(octx->error_fp,
+                       "# Warning: table %s %s was created by a newer version of nftables? Content may be incomplete!\n",
+                       family, table->handle.table.name);
 
        nft_print(octx, "table %s %s {", family, table->handle.table.name);
        if (nft_output_handle(octx) || table->flags & TABLE_F_OWNER)