]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
JSON: Add metainfo object to all output
authorPhil Sutter <phil@nwl.cc>
Wed, 29 Aug 2018 14:23:28 +0000 (16:23 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Thu, 30 Aug 2018 10:19:36 +0000 (12:19 +0200)
Right now this object merely contains the nftables version and release
name as well as a JSON schema version, but it could be extended
arbitrarily. In the future, this will also allow for non-compatible
schema changes should the need for this arise.

Adjust the parser to accept metainfo objects and make it verify
json_schema_version to be less than or equal to the one hard-coded in
the library.

Signed-off-by: Phil Sutter <phil@nwl.cc>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
doc/libnftables-json.adoc
include/json.h
src/json.c
src/parser_json.c

index c174a35487d46380ce85ece8c84a3bf22f95c5b2..59bac17fd005113dc1318084f6bb411ab359fbb2 100644 (file)
@@ -16,13 +16,14 @@ libnftables-json - Supported JSON schema by libnftables
 
 'CMD_OBJECTS' := 'CMD_OBJECT' [ *,* 'CMD_OBJECTS' ]
 
-'CMD_OBJECT' := *{* 'CMD'*:* 'LIST_OBJECT' *}*
+'CMD_OBJECT' := *{* 'CMD'*:* 'LIST_OBJECT' *}* | 'METAINFO_OBJECT'
 
 'CMD' := *"add"* | *"replace"* | *"create"* | *"insert"* | *"delete"* |
          *"list"* | *"reset"* | *"flush"* | *"rename"*
 
 'LIST_OBJECT' := 'TABLE' | 'CHAIN' | 'RULE' | 'SET' | 'MAP' | 'ELEMENT' |
-                'FLOWTABLE' | 'COUNTER' | 'QUOTA' | 'CT_HELPER' | 'LIMIT'
+                'FLOWTABLE' | 'COUNTER' | 'QUOTA' | 'CT_HELPER' | 'LIMIT' |
+                'METAINFO_OBJECT'
 
 == DESCRIPTION
 libnftables supports JSON formatted input and output. This is implemented as an
@@ -47,6 +48,26 @@ It's value is a ruleset element - basically identical to output elements apart
 from certain properties which may be interpreted differently or are required
 when output generally omits them.
 
+== METAINFO OBJECT
+In output, the first object in *nftables* array is a special one containing
+library information. Its content is as follows:
+
+[verse]
+*{ "metainfo": {
+       "version":* 'STRING'*,
+       "release_name":* 'STRING'*,
+       "json_schema_version":* 'NUMBER'
+*}}*
+
+The values of *version* and *release_name* properties are equal to the package
+version and release name as printed by *nft -v*. The value of
+*json_schema_version* property is an integer indicating the schema version.
+
+If supplied in library input, the parser will verify *json_schema_version* value
+to not exceed the internally hardcoded one (to make sure the given schema is
+fully understood). In future, a lower number than the internal one may activate
+compatibility mode to parse outdated and incompatible JSON input.
+
 == COMMAND OBJECTS
 The structure accepts an arbitrary amount of commands which are interpreted in
 order of appearance. For instance, the following standard syntax input:
index e64151de66c05d4905a6b8195c7611c8b25565bc..66f60e76aa83e15ab3913b60765bafbfcd6638ca 100644 (file)
@@ -15,6 +15,8 @@ struct table;
 
 #ifdef HAVE_LIBJANSSON
 
+#define JSON_SCHEMA_VERSION 1
+
 #include <jansson.h>
 
 json_t *binop_expr_json(const struct expr *expr, struct output_ctx *octx);
index 2a13dfe785e81a811eda82209c9c0c8a6c8ac2ff..84bdaa39c0d3161884e14650c8059c364161eacb 100644 (file)
@@ -1530,6 +1530,14 @@ static json_t *do_list_flowtables_json(struct netlink_ctx *ctx, struct cmd *cmd)
        return root;
 }
 
+static json_t *generate_json_metainfo(void)
+{
+       return json_pack("{s: {s:s, s:s, s:i}}", "metainfo",
+                        "version", PACKAGE_VERSION,
+                        "release_name", RELEASE_NAME,
+                        "json_schema_version", JSON_SCHEMA_VERSION);
+}
+
 int do_command_list_json(struct netlink_ctx *ctx, struct cmd *cmd)
 {
        struct table *table = NULL;
@@ -1596,10 +1604,15 @@ int do_command_list_json(struct netlink_ctx *ctx, struct cmd *cmd)
                BUG("invalid command object type %u\n", cmd->obj);
        }
 
-       if (json_is_array(root) && !json_array_size(root)) {
-               json_decref(root);
-               root = json_null();
+       if (!json_is_array(root)) {
+               json_t *tmp = json_array();
+
+               json_array_append_new(tmp, root);
+               root = tmp;
        }
+
+       json_array_insert_new(root, 0, generate_json_metainfo());
+
        root = json_pack("{s:o}", "nftables", root);
        json_dumpf(root, ctx->octx->output_fp, 0);
        json_decref(root);
index 6870434e952a40a560780ef553c13b9e2c1fb8cf..6af9d0755df05ce0703d6cd0fc0a9ace1878cd9e 100644 (file)
@@ -3118,6 +3118,22 @@ static struct cmd *json_parse_cmd(struct json_ctx *ctx, json_t *root)
        return NULL;
 }
 
+static int json_verify_metainfo(struct json_ctx *ctx, json_t *root)
+{
+       int schema_version;
+
+       if (!json_unpack(root, "{s:i}", "json_schema_version", &schema_version))
+                       return 0;
+
+       if (schema_version > JSON_SCHEMA_VERSION) {
+               json_error(ctx, "Schema version %d not supported, maximum supported version is %d\n",
+                          schema_version, JSON_SCHEMA_VERSION);
+               return 1;
+       }
+
+       return 0;
+}
+
 static int __json_parse(struct json_ctx *ctx, json_t *root)
 {
        struct eval_ctx ectx = {
@@ -3142,11 +3158,22 @@ static int __json_parse(struct json_ctx *ctx, json_t *root)
                /* this is more or less from parser_bison.y:716 */
                LIST_HEAD(list);
                struct cmd *cmd;
+               json_t *tmp2;
 
                if (!json_is_object(value)) {
                        json_error(ctx, "Unexpected command array element of type %s, expected object.", json_typename(value));
                        return -1;
                }
+
+               tmp2 = json_object_get(value, "metainfo");
+               if (tmp2) {
+                       if (json_verify_metainfo(ctx, tmp2)) {
+                               json_error(ctx, "Metainfo verification failed.");
+                               return -1;
+                       }
+                       continue;
+               }
+
                cmd = json_parse_cmd(ctx, value);
 
                if (!cmd) {