nftables/SOURCES/0005-monitor-Use-libnftables-JSON-output.patch
2021-10-08 14:03:04 +00:00

653 lines
18 KiB
Diff

From 53693c43d94dddf1ae1a0e69bfa953fba2c098e0 Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Thu, 11 Oct 2018 17:49:00 +0200
Subject: [PATCH] monitor: Use libnftables JSON output
This switches 'nft monitor' JSON output from using libnftnl's to
libnftables' implementation.
Signed-off-by: Phil Sutter <phil@nwl.cc>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
(cherry picked from commit 9e88aae28e9f44d010f3ecf7577357f4c0e7d622)
Signed-off-by: Phil Sutter <psutter@redhat.com>
---
include/json.h | 51 +++++++++
src/json.c | 57 ++++++++++
src/monitor.c | 281 +++++++++++++++++++++++++------------------------
src/rule.c | 2 -
4 files changed, 251 insertions(+), 140 deletions(-)
diff --git a/include/json.h b/include/json.h
index ae3938142aeac..af0f72f13dd60 100644
--- a/include/json.h
+++ b/include/json.h
@@ -9,9 +9,11 @@ struct expr;
struct netlink_ctx;
struct rule;
struct set;
+struct obj;
struct stmt;
struct symbol_table;
struct table;
+struct netlink_mon_handler;
#ifdef HAVE_LIBJANSSON
@@ -81,6 +83,19 @@ int nft_parse_json_buffer(struct nft_ctx *nft, char *buf, size_t buflen,
int nft_parse_json_filename(struct nft_ctx *nft, const char *filename,
struct list_head *msgs, struct list_head *cmds);
+void monitor_print_table_json(struct netlink_mon_handler *monh,
+ const char *cmd, struct table *t);
+void monitor_print_chain_json(struct netlink_mon_handler *monh,
+ const char *cmd, struct chain *c);
+void monitor_print_set_json(struct netlink_mon_handler *monh,
+ const char *cmd, struct set *s);
+void monitor_print_element_json(struct netlink_mon_handler *monh,
+ const char *cmd, struct set *s);
+void monitor_print_obj_json(struct netlink_mon_handler *monh,
+ const char *cmd, struct obj *o);
+void monitor_print_rule_json(struct netlink_mon_handler *monh,
+ const char *cmd, struct rule *r);
+
#else /* ! HAVE_LIBJANSSON */
typedef void json_t;
@@ -176,6 +191,42 @@ nft_parse_json_filename(struct nft_ctx *nft, const char *filename,
return -EINVAL;
}
+static inline void monitor_print_table_json(struct netlink_mon_handler *monh,
+ const char *cmd, struct table *t)
+{
+ /* empty */
+}
+
+static inline void monitor_print_chain_json(struct netlink_mon_handler *monh,
+ const char *cmd, struct chain *c)
+{
+ /* empty */
+}
+
+static inline void monitor_print_set_json(struct netlink_mon_handler *monh,
+ const char *cmd, struct set *s)
+{
+ /* empty */
+}
+
+static inline void monitor_print_element_json(struct netlink_mon_handler *monh,
+ const char *cmd, struct set *s)
+{
+ /* empty */
+}
+
+static inline void monitor_print_obj_json(struct netlink_mon_handler *monh,
+ const char *cmd, struct obj *o)
+{
+ /* empty */
+}
+
+static inline void monitor_print_rule_json(struct netlink_mon_handler *monh,
+ const char *cmd, struct rule *r)
+{
+ /* empty */
+}
+
#endif /* HAVE_LIBJANSSON */
#endif /* NFTABLES_JSON_H */
diff --git a/src/json.c b/src/json.c
index af157212c081e..7d89754bd666d 100644
--- a/src/json.c
+++ b/src/json.c
@@ -147,6 +147,19 @@ static json_t *set_print_json(struct output_ctx *octx, const struct set *set)
return json_pack("{s:o}", type, root);
}
+/* XXX: Merge with set_print_json()? */
+static json_t *element_print_json(struct output_ctx *octx,
+ const struct set *set)
+{
+ json_t *root = expr_print_json(set->init, octx);
+
+ return json_pack("{s: {s:s, s:s, s:s, s:o}}", "element",
+ "family", family2str(set->handle.family),
+ "table", set->handle.table.name,
+ "name", set->handle.set.name,
+ "elem", root);
+}
+
static json_t *stmt_print_json(const struct stmt *stmt, struct output_ctx *octx)
{
char buf[1024];
@@ -1554,3 +1567,47 @@ int do_command_list_json(struct netlink_ctx *ctx, struct cmd *cmd)
json_decref(root);
return 0;
}
+
+static void monitor_print_json(struct netlink_mon_handler *monh,
+ const char *cmd, json_t *obj)
+{
+ obj = json_pack("{s:o}", cmd, obj);
+ json_dumpf(obj, monh->ctx->octx->output_fp, 0);
+ json_decref(obj);
+}
+
+void monitor_print_table_json(struct netlink_mon_handler *monh,
+ const char *cmd, struct table *t)
+{
+ monitor_print_json(monh, cmd, table_print_json(monh->ctx->octx, t));
+}
+
+void monitor_print_chain_json(struct netlink_mon_handler *monh,
+ const char *cmd, struct chain *c)
+{
+ monitor_print_json(monh, cmd, chain_print_json(monh->ctx->octx, c));
+}
+
+void monitor_print_set_json(struct netlink_mon_handler *monh,
+ const char *cmd, struct set *s)
+{
+ monitor_print_json(monh, cmd, set_print_json(monh->ctx->octx, s));
+}
+
+void monitor_print_element_json(struct netlink_mon_handler *monh,
+ const char *cmd, struct set *s)
+{
+ monitor_print_json(monh, cmd, element_print_json(monh->ctx->octx, s));
+}
+
+void monitor_print_obj_json(struct netlink_mon_handler *monh,
+ const char *cmd, struct obj *o)
+{
+ monitor_print_json(monh, cmd, obj_print_json(monh->ctx->octx, o));
+}
+
+void monitor_print_rule_json(struct netlink_mon_handler *monh,
+ const char *cmd, struct rule *r)
+{
+ monitor_print_json(monh, cmd, rule_print_json(monh->ctx->octx, r));
+}
diff --git a/src/monitor.c b/src/monitor.c
index 3e70b89f0b2ab..213c40d119b4c 100644
--- a/src/monitor.c
+++ b/src/monitor.c
@@ -38,6 +38,7 @@
#include <utils.h>
#include <erec.h>
#include <iface.h>
+#include <json.h>
#define nft_mon_print(monh, ...) nft_print(monh->ctx->octx, __VA_ARGS__)
@@ -127,18 +128,39 @@ static uint32_t netlink_msg2nftnl_of(uint32_t msg)
case NFT_MSG_NEWSET:
case NFT_MSG_NEWSETELEM:
case NFT_MSG_NEWRULE:
+ case NFT_MSG_NEWOBJ:
+ case NFT_MSG_NEWFLOWTABLE:
return NFTNL_OF_EVENT_NEW;
case NFT_MSG_DELTABLE:
case NFT_MSG_DELCHAIN:
case NFT_MSG_DELSET:
case NFT_MSG_DELSETELEM:
case NFT_MSG_DELRULE:
+ case NFT_MSG_DELOBJ:
+ case NFT_MSG_DELFLOWTABLE:
return NFTNL_OF_EVENT_DEL;
}
return 0;
}
+static const char *nftnl_of2cmd(uint32_t of)
+{
+ switch (of) {
+ case NFTNL_OF_EVENT_NEW:
+ return "add";
+ case NFTNL_OF_EVENT_DEL:
+ return "delete";
+ default:
+ return "???";
+ }
+}
+
+static const char *netlink_msg2cmd(uint32_t msg)
+{
+ return nftnl_of2cmd(netlink_msg2nftnl_of(msg));
+}
+
static void nlr_for_each_set(struct nftnl_rule *nlr,
void (*cb)(struct set *s, void *data),
void *data, struct nft_cache *cache)
@@ -179,34 +201,29 @@ static int netlink_events_table_cb(const struct nlmsghdr *nlh, int type,
struct netlink_mon_handler *monh)
{
struct nftnl_table *nlt;
- uint32_t family;
+ struct table *t;
+ const char *cmd;
nlt = netlink_table_alloc(nlh);
+ t = netlink_delinearize_table(monh->ctx, nlt);
+ cmd = netlink_msg2cmd(type);
switch (monh->format) {
case NFTNL_OUTPUT_DEFAULT:
- if (type == NFT_MSG_NEWTABLE) {
- nft_mon_print(monh, "add table ");
- } else {
- nft_mon_print(monh, "delete table ");
- }
+ nft_mon_print(monh, "%s table ", cmd);
- family = nftnl_table_get_u32(nlt, NFTNL_TABLE_FAMILY);
-
- nft_mon_print(monh, "%s %s", family2str(family),
- nftnl_table_get_str(nlt, NFTNL_TABLE_NAME));
+ nft_mon_print(monh, "%s %s", family2str(t->handle.family),
+ t->handle.table.name);
if (monh->ctx->octx->handle > 0)
nft_mon_print(monh, " # handle %" PRIu64 "",
- nftnl_table_get_u64(nlt, NFTNL_TABLE_HANDLE));
- nft_mon_print(monh, "\n");
+ t->handle.handle.id);
break;
case NFTNL_OUTPUT_JSON:
- nftnl_table_fprintf(monh->ctx->octx->output_fp, nlt,
- monh->format, netlink_msg2nftnl_of(type));
- nft_mon_print(monh, "\n");
+ monitor_print_table_json(monh, cmd, t);
break;
}
-
+ nft_mon_print(monh, "\n");
+ table_free(t);
nftnl_table_free(nlt);
return MNL_CB_OK;
}
@@ -216,35 +233,34 @@ static int netlink_events_chain_cb(const struct nlmsghdr *nlh, int type,
{
struct nftnl_chain *nlc;
struct chain *c;
- uint32_t family;
+ const char *cmd;
nlc = netlink_chain_alloc(nlh);
+ c = netlink_delinearize_chain(monh->ctx, nlc);
+ cmd = netlink_msg2cmd(type);
switch (monh->format) {
case NFTNL_OUTPUT_DEFAULT:
+ nft_mon_print(monh, "%s ", cmd);
+
switch (type) {
case NFT_MSG_NEWCHAIN:
- nft_mon_print(monh, "add ");
-
- c = netlink_delinearize_chain(monh->ctx, nlc);
chain_print_plain(c, monh->ctx->octx);
- chain_free(c);
break;
case NFT_MSG_DELCHAIN:
- family = nftnl_chain_get_u32(nlc, NFTNL_CHAIN_FAMILY);
- nft_mon_print(monh, "delete chain %s %s %s\n", family2str(family),
- nftnl_chain_get_str(nlc, NFTNL_CHAIN_TABLE),
- nftnl_chain_get_str(nlc, NFTNL_CHAIN_NAME));
+ nft_mon_print(monh, "chain %s %s %s",
+ family2str(c->handle.family),
+ c->handle.table.name,
+ c->handle.chain.name);
break;
}
break;
case NFTNL_OUTPUT_JSON:
- nftnl_chain_fprintf(monh->ctx->octx->output_fp, nlc,
- monh->format, netlink_msg2nftnl_of(type));
- nft_mon_print(monh, "\n");
+ monitor_print_chain_json(monh, cmd, c);
break;
}
-
+ nft_mon_print(monh, "\n");
+ chain_free(c);
nftnl_chain_free(nlc);
return MNL_CB_OK;
}
@@ -253,43 +269,44 @@ static int netlink_events_set_cb(const struct nlmsghdr *nlh, int type,
struct netlink_mon_handler *monh)
{
struct nftnl_set *nls;
+ const char *family, *cmd;
struct set *set;
- uint32_t family, flags;
+ uint32_t flags;
nls = netlink_set_alloc(nlh);
flags = nftnl_set_get_u32(nls, NFTNL_SET_FLAGS);
if (flags & NFT_SET_ANONYMOUS)
goto out;
+ set = netlink_delinearize_set(monh->ctx, nls);
+ if (set == NULL) {
+ nftnl_set_free(nls);
+ return MNL_CB_ERROR;
+ }
+ family = family2str(set->handle.family);
+ cmd = netlink_msg2cmd(type);
+
switch (monh->format) {
case NFTNL_OUTPUT_DEFAULT:
+ nft_mon_print(monh, "%s ", cmd);
+
switch (type) {
case NFT_MSG_NEWSET:
- nft_mon_print(monh, "add ");
- set = netlink_delinearize_set(monh->ctx, nls);
- if (set == NULL) {
- nftnl_set_free(nls);
- return MNL_CB_ERROR;
- }
set_print_plain(set, monh->ctx->octx);
- set_free(set);
- nft_mon_print(monh, "\n");
break;
case NFT_MSG_DELSET:
- family = nftnl_set_get_u32(nls, NFTNL_SET_FAMILY);
- nft_mon_print(monh, "delete set %s %s %s\n",
- family2str(family),
- nftnl_set_get_str(nls, NFTNL_SET_TABLE),
- nftnl_set_get_str(nls, NFTNL_SET_NAME));
+ nft_mon_print(monh, "set %s %s %s", family,
+ set->handle.table.name,
+ set->handle.set.name);
break;
}
break;
case NFTNL_OUTPUT_JSON:
- nftnl_set_fprintf(monh->ctx->octx->output_fp, nls,
- monh->format, netlink_msg2nftnl_of(type));
- nft_mon_print(monh, "\n");
+ monitor_print_set_json(monh, cmd, set);
break;
}
+ nft_mon_print(monh, "\n");
+ set_free(set);
out:
nftnl_set_free(nls);
return MNL_CB_OK;
@@ -360,13 +377,14 @@ static int netlink_events_setelem_cb(const struct nlmsghdr *nlh, int type,
struct nftnl_set *nls;
struct set *dummyset;
struct set *set;
- const char *setname, *table;
+ const char *setname, *table, *cmd;
uint32_t family;
nls = netlink_setelem_alloc(nlh);
table = nftnl_set_get_str(nls, NFTNL_SET_TABLE);
setname = nftnl_set_get_str(nls, NFTNL_SET_NAME);
family = nftnl_set_get_u32(nls, NFTNL_SET_FAMILY);
+ cmd = netlink_msg2cmd(type);
set = set_lookup_global(family, table, setname, monh->cache);
if (set == NULL) {
@@ -374,70 +392,63 @@ static int netlink_events_setelem_cb(const struct nlmsghdr *nlh, int type,
goto out;
}
- switch (monh->format) {
- case NFTNL_OUTPUT_DEFAULT:
- if (set->flags & NFT_SET_ANONYMOUS)
- goto out;
-
- /* we want to 'delinearize' the set_elem, but don't
- * modify the original cached set. This path is only
- * used by named sets, so use a dummy set.
- */
- dummyset = set_alloc(monh->loc);
- dummyset->key = expr_clone(set->key);
- dummyset->datatype = set->datatype;
- dummyset->flags = set->flags;
- dummyset->init = set_expr_alloc(monh->loc, set);
+ if (set->flags & NFT_SET_ANONYMOUS)
+ goto out;
- nlsei = nftnl_set_elems_iter_create(nls);
- if (nlsei == NULL)
- memory_allocation_error();
+ /* we want to 'delinearize' the set_elem, but don't
+ * modify the original cached set. This path is only
+ * used by named sets, so use a dummy set.
+ */
+ dummyset = set_alloc(monh->loc);
+ dummyset->key = expr_clone(set->key);
+ dummyset->datatype = set->datatype;
+ dummyset->flags = set->flags;
+ dummyset->init = set_expr_alloc(monh->loc, set);
- nlse = nftnl_set_elems_iter_next(nlsei);
- while (nlse != NULL) {
- if (netlink_event_ignore_range_event(nlse)) {
- set_free(dummyset);
- nftnl_set_elems_iter_destroy(nlsei);
- goto out;
- }
- if (netlink_delinearize_setelem(nlse, dummyset,
- monh->cache) < 0) {
- set_free(dummyset);
- nftnl_set_elems_iter_destroy(nlsei);
- goto out;
- }
- nlse = nftnl_set_elems_iter_next(nlsei);
- }
- nftnl_set_elems_iter_destroy(nlsei);
+ nlsei = nftnl_set_elems_iter_create(nls);
+ if (nlsei == NULL)
+ memory_allocation_error();
- if (netlink_event_range_cache(set, dummyset)) {
+ nlse = nftnl_set_elems_iter_next(nlsei);
+ while (nlse != NULL) {
+ if (netlink_event_ignore_range_event(nlse)) {
set_free(dummyset);
+ nftnl_set_elems_iter_destroy(nlsei);
goto out;
}
-
- switch (type) {
- case NFT_MSG_NEWSETELEM:
- nft_mon_print(monh, "add ");
- break;
- case NFT_MSG_DELSETELEM:
- nft_mon_print(monh, "delete ");
- break;
- default:
+ if (netlink_delinearize_setelem(nlse, dummyset,
+ monh->cache) < 0) {
set_free(dummyset);
+ nftnl_set_elems_iter_destroy(nlsei);
goto out;
}
- nft_mon_print(monh, "element %s %s %s ", family2str(family), table, setname);
- expr_print(dummyset->init, monh->ctx->octx);
- nft_mon_print(monh, "\n");
+ nlse = nftnl_set_elems_iter_next(nlsei);
+ }
+ nftnl_set_elems_iter_destroy(nlsei);
+ if (netlink_event_range_cache(set, dummyset)) {
set_free(dummyset);
+ goto out;
+ }
+
+ switch (monh->format) {
+ case NFTNL_OUTPUT_DEFAULT:
+ nft_mon_print(monh, "%s element %s %s %s ",
+ cmd, family2str(family), table, setname);
+ expr_print(dummyset->init, monh->ctx->octx);
break;
case NFTNL_OUTPUT_JSON:
- nftnl_set_fprintf(monh->ctx->octx->output_fp, nls,
- monh->format, netlink_msg2nftnl_of(type));
- nft_mon_print(monh, "\n");
+ dummyset->handle.family = family;
+ dummyset->handle.set.name = setname;
+ dummyset->handle.table.name = table;
+ monitor_print_element_json(monh, cmd, dummyset);
+ /* prevent set_free() from trying to free those */
+ dummyset->handle.set.name = NULL;
+ dummyset->handle.table.name = NULL;
break;
}
+ nft_mon_print(monh, "\n");
+ set_free(dummyset);
out:
nftnl_set_free(nls);
return MNL_CB_OK;
@@ -446,43 +457,43 @@ out:
static int netlink_events_obj_cb(const struct nlmsghdr *nlh, int type,
struct netlink_mon_handler *monh)
{
+ const char *family, *cmd;
struct nftnl_obj *nlo;
- uint32_t family;
struct obj *obj;
nlo = netlink_obj_alloc(nlh);
+ obj = netlink_delinearize_obj(monh->ctx, nlo);
+ if (obj == NULL) {
+ nftnl_obj_free(nlo);
+ return MNL_CB_ERROR;
+ }
+ family = family2str(obj->handle.family);
+ cmd = netlink_msg2cmd(type);
+
switch (monh->format) {
case NFTNL_OUTPUT_DEFAULT:
+ nft_mon_print(monh, "%s ", cmd);
+
switch (type) {
case NFT_MSG_NEWOBJ:
- nft_mon_print(monh, "add ");
- obj = netlink_delinearize_obj(monh->ctx, nlo);
- if (obj == NULL) {
- nftnl_obj_free(nlo);
- return MNL_CB_ERROR;
- }
obj_print_plain(obj, monh->ctx->octx);
- obj_free(obj);
- nft_mon_print(monh, "\n");
break;
case NFT_MSG_DELOBJ:
- family = nftnl_obj_get_u32(nlo, NFTNL_OBJ_FAMILY);
- nft_mon_print(monh, "delete %s %s %s %s\n",
- obj_type_name(nftnl_obj_get_u32(nlo, NFTNL_OBJ_TYPE)),
- family2str(family),
- nftnl_obj_get_str(nlo, NFTNL_OBJ_TABLE),
- nftnl_obj_get_str(nlo, NFTNL_OBJ_NAME));
+ nft_mon_print(monh, "%s %s %s %s",
+ obj_type_name(obj->type),
+ family,
+ obj->handle.table.name,
+ obj->handle.obj.name);
break;
}
break;
case NFTNL_OUTPUT_JSON:
- nftnl_obj_fprintf(monh->ctx->octx->output_fp, nlo,
- monh->format, netlink_msg2nftnl_of(type));
- nft_mon_print(monh, "\n");
+ monitor_print_obj_json(monh, cmd, obj);
break;
}
-
+ nft_mon_print(monh, "\n");
+ obj_free(obj);
nftnl_obj_free(nlo);
return MNL_CB_OK;
}
@@ -496,48 +507,42 @@ static void rule_map_decompose_cb(struct set *s, void *data)
static int netlink_events_rule_cb(const struct nlmsghdr *nlh, int type,
struct netlink_mon_handler *monh)
{
+ const char *family, *cmd;
struct nftnl_rule *nlr;
- const char *family;
- const char *table;
- const char *chain;
struct rule *r;
- uint64_t handle;
- uint32_t fam;
nlr = netlink_rule_alloc(nlh);
+ r = netlink_delinearize_rule(monh->ctx, nlr);
+ nlr_for_each_set(nlr, rule_map_decompose_cb, NULL, monh->cache);
+ cmd = netlink_msg2cmd(type);
+
switch (monh->format) {
case NFTNL_OUTPUT_DEFAULT:
- fam = nftnl_rule_get_u32(nlr, NFTNL_RULE_FAMILY);
- family = family2str(fam);
- table = nftnl_rule_get_str(nlr, NFTNL_RULE_TABLE);
- chain = nftnl_rule_get_str(nlr, NFTNL_RULE_CHAIN);
- handle = nftnl_rule_get_u64(nlr, NFTNL_RULE_HANDLE);
+ family = family2str(r->handle.family);
+
+ nft_mon_print(monh, "%s rule %s %s %s ",
+ cmd,
+ family,
+ r->handle.table.name,
+ r->handle.chain.name);
switch (type) {
case NFT_MSG_NEWRULE:
- r = netlink_delinearize_rule(monh->ctx, nlr);
- nlr_for_each_set(nlr, rule_map_decompose_cb, NULL,
- monh->cache);
-
- nft_mon_print(monh, "add rule %s %s %s ", family, table, chain);
rule_print(r, monh->ctx->octx);
- nft_mon_print(monh, "\n");
- rule_free(r);
break;
case NFT_MSG_DELRULE:
- nft_mon_print(monh, "delete rule %s %s %s handle %u\n",
- family, table, chain, (unsigned int)handle);
+ nft_mon_print(monh, "handle %" PRIu64,
+ r->handle.handle.id);
break;
}
break;
case NFTNL_OUTPUT_JSON:
- nftnl_rule_fprintf(monh->ctx->octx->output_fp, nlr,
- monh->format, netlink_msg2nftnl_of(type));
- nft_mon_print(monh, "\n");
+ monitor_print_rule_json(monh, cmd, r);
break;
}
-
+ nft_mon_print(monh, "\n");
+ rule_free(r);
nftnl_rule_free(nlr);
return MNL_CB_OK;
}
diff --git a/src/rule.c b/src/rule.c
index eb06302d4f223..3065cc5474bbf 100644
--- a/src/rule.c
+++ b/src/rule.c
@@ -812,8 +812,6 @@ void chain_print_plain(const struct chain *chain, struct output_ctx *octx)
}
if (octx->handle > 0)
nft_print(octx, " # handle %" PRIu64, chain->handle.handle.id);
-
- nft_print(octx, "\n");
}
struct table *table_alloc(void)
--
2.19.0