Upon listing a table which was created by a newer version of nftables, warn about the potentially incomplete content. Suggested-by: Florian Westphal <fw@xxxxxxxxx> Cc: Dan Winship <danwinship@xxxxxxxxxx> Signed-off-by: Phil Sutter <phil@xxxxxx> --- include/nft.h | 2 ++ include/rule.h | 1 + src/mnl.c | 18 ++++++++++++------ src/netlink.c | 25 ++++++++++++++++++++++++- src/rule.c | 4 ++++ 5 files changed, 43 insertions(+), 7 deletions(-) diff --git a/include/nft.h b/include/nft.h index a2d62dbf4808a..b406a68ffeb18 100644 --- a/include/nft.h +++ b/include/nft.h @@ -15,4 +15,6 @@ * something we frequently need to do and it's intentional. */ #define free_const(ptr) free((void *)(ptr)) +#define NFTNL_UDATA_TABLE_NFTVER 1 + #endif /* NFTABLES_NFT_H */ diff --git a/include/rule.h b/include/rule.h index 85a0d9c0b524b..c4fecb2a8faeb 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 ee51933798580..174e97ccb74f6 100644 --- a/src/mnl.c +++ b/src/mnl.c @@ -1069,24 +1069,30 @@ 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_strz(udbuf, NFTNL_UDATA_TABLE_NFTVER, + PACKAGE_VERSION)) + 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 86ca32144f029..88d4cf73352f6 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -751,6 +751,7 @@ static int table_parse_udata_cb(const struct nftnl_udata *attr, void *data) switch (type) { case NFTNL_UDATA_TABLE_COMMENT: + case NFTNL_UDATA_TABLE_NFTVER: if (value[len - 1] != '\0') return -1; break; @@ -761,10 +762,28 @@ static int table_parse_udata_cb(const struct nftnl_udata *attr, void *data) return 0; } +static int version_cmp(const char *ver_a, const char *ver_b) +{ + int ax, ay, az, bx, by, bz; + + if (sscanf(ver_a, "%d.%d.%d", &ax, &ay, &az) != 3 || + sscanf(ver_b, "%d.%d.%d", &bx, &by, &bz) != 3) + return 0; + + if (ax != bx) + return ax - bx; + if (ay != by) + return ay - by; + if (az != bz) + return az - bz; + + return strcmp(ver_a, ver_b); +} + struct table *netlink_delinearize_table(struct netlink_ctx *ctx, const struct nftnl_table *nlt) { - const struct nftnl_udata *ud[NFTNL_UDATA_TABLE_MAX + 1] = {}; + const struct nftnl_udata *ud[NFTNL_UDATA_TABLE_MAX + 2] = {}, *udtmp; struct table *table; const char *udata; uint32_t ulen; @@ -785,6 +804,10 @@ 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])); + udtmp = ud[NFTNL_UDATA_TABLE_NFTVER]; + if (udtmp && version_cmp(PACKAGE_VERSION, + nftnl_udata_get(udtmp)) < 0) + table->is_from_future = true; } return table; diff --git a/src/rule.c b/src/rule.c index 80315837baf06..9b9a7e1e080ab 100644 --- a/src/rule.c +++ b/src/rule.c @@ -1285,6 +1285,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) -- 2.49.0