]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
monitor: Use libnftables JSON output
authorPhil Sutter <phil@nwl.cc>
Thu, 11 Oct 2018 15:49:00 +0000 (17:49 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Mon, 15 Oct 2018 11:37:51 +0000 (13:37 +0200)
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>
include/json.h
src/json.c
src/monitor.c
src/rule.c

index 663375489bc5181d8e8e4c797b4962098606ce9e..d2dc92d963693c2bace3a1df9e6a27463fb12ce9 100644 (file)
@@ -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
 
@@ -88,6 +90,19 @@ int nft_parse_json_buffer(struct nft_ctx *nft, const char *buf,
 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;
@@ -183,6 +198,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 */
index a0a2b9db65b0bf81471a4df7cd32d68a0344f6af..f5d97c623fb3a529ebc284b2934c861ea6fbb72c 100644 (file)
@@ -148,6 +148,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];
@@ -1714,3 +1727,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));
+}
index 3e70b89f0b2abffeface7cd9a5b7ca5deb54c595..213c40d119b4c54076b231a53026b116a6f84b10 100644 (file)
@@ -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;
 }
index f677562014b9bcfab210d6c3b1b9d5c59f8646cd..e1b004c7692fb9d9ce65ff6501fd67569344f684 100644 (file)
@@ -1049,8 +1049,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)