From: Phil Sutter Date: Mon, 12 May 2025 20:59:26 +0000 (+0200) Subject: table: Embed creating nft version into userdata X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=64c07e38f0494093a399a68a31056f5866c4d705;p=thirdparty%2Fnftables.git table: Embed creating nft version into userdata Upon listing a table which was created by a newer version of nftables, warn about the potentially incomplete content. Suggested-by: Florian Westphal Cc: Dan Winship Signed-off-by: Phil Sutter Acked-by: Pablo Neira Ayuso --- diff --git a/.gitignore b/.gitignore index a62e31f3..1e3bc514 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,7 @@ autom4te.cache build-aux/ libnftables.pc libtool +nftversion.h # cscope files /cscope.* diff --git a/Makefile.am b/Makefile.am index 51dadbe6..5190a49a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -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 = \ diff --git a/configure.ac b/configure.ac index 3a751cb0..da16a6e2 100644 --- a/configure.ac +++ b/configure.ac @@ -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 \ diff --git a/include/rule.h b/include/rule.h index 498a88bf..8d2f29d0 100644 --- a/include/rule.h +++ b/include/rule.h @@ -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); diff --git a/src/mnl.c b/src/mnl.c index 273cefe8..984dcac2 100644 --- a/src/mnl.c +++ b/src/mnl.c @@ -10,6 +10,7 @@ #include #include +#include #include #include @@ -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, diff --git a/src/netlink.c b/src/netlink.c index 5876c089..5511d988 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -10,6 +10,7 @@ */ #include +#include #include #include @@ -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; diff --git a/src/rule.c b/src/rule.c index e6216bca..ceb56488 100644 --- a/src/rule.c +++ b/src/rule.c @@ -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)