Having to use numerical values for ttl property in JSON is not practical as these values are arbitrary and meaningful only in netfilter. Instead align JSON output/input with standard API, accepting names for TTL matching strategy. Also add missing documentation in libnftables-json man page and fix JSON equivalent in tests/py. Fixes: 03eafe098d5ee ("osf: add ttl option support") Signed-off-by: Phil Sutter <phil@xxxxxx> --- doc/libnftables-json.adoc | 24 ++++++++++++++++++++++++ src/json.c | 13 ++++++++++++- src/parser_json.c | 19 +++++++++++++++---- tests/py/inet/osf.t.json | 35 ++++++++++++++++++++++++++++++++--- 4 files changed, 83 insertions(+), 8 deletions(-) diff --git a/doc/libnftables-json.adoc b/doc/libnftables-json.adoc index 98303b357f10c..ea5fbe818302f 100644 --- a/doc/libnftables-json.adoc +++ b/doc/libnftables-json.adoc @@ -1288,3 +1288,27 @@ ____ ____ Construct a reference to packet's socket. + +=== OSF +[verse] +____ +*{ "osf": { + "key":* 'OSF_KEY'*, + "ttl":* 'OSF_TTL' +*}}* + +'OSF_KEY' := *"name"* +'OSF_TTL' := *"loose"* | *"skip"* +____ + +Perform OS fingerprinting. This expression is typically used in LHS of a *match* +statement. + +*key*:: + What part of the fingerprint info to match against. At this point, only + the OS name is supported. +*ttl*:: + Define how packet's TTL value is to be matched. This property is + optional. If omitted, TTL value has to match exactly. A value of *loose* + accepts TTL values less than the fingerprint one. A value of *skip* + omits TTL value comparison entirely. diff --git a/src/json.c b/src/json.c index cea9f19cd9982..d21536afd714e 100644 --- a/src/json.c +++ b/src/json.c @@ -857,7 +857,18 @@ json_t *socket_expr_json(const struct expr *expr, struct output_ctx *octx) json_t *osf_expr_json(const struct expr *expr, struct output_ctx *octx) { - return json_pack("{s:{s:i, s:s}}", "osf", "ttl", expr->osf.ttl, "key", "name"); + json_t *root = json_pack("{s:s}", "key", "name"); + + switch (expr->osf.ttl) { + case 1: + json_object_set_new(root, "ttl", json_string("loose")); + break; + case 2: + json_object_set_new(root, "ttl", json_string("skip")); + break; + } + + return json_pack("{s:o}", "osf", root); } json_t *xfrm_expr_json(const struct expr *expr, struct output_ctx *octx) diff --git a/src/parser_json.c b/src/parser_json.c index fc0dc9a9e4046..46a02fe14de03 100644 --- a/src/parser_json.c +++ b/src/parser_json.c @@ -375,14 +375,25 @@ static struct expr *json_parse_meta_expr(struct json_ctx *ctx, static struct expr *json_parse_osf_expr(struct json_ctx *ctx, const char *type, json_t *root) { - const char *key; - uint8_t ttl; + const char *key, *ttl; + uint8_t ttlval = 0; - if (json_unpack_err(ctx, root, "{s:i, s:s}", "ttl", ttl,"key", &key)) + if (json_unpack_err(ctx, root, "{s:s}", "key", &key)) return NULL; + if (!json_unpack(root, "{s:s}", "ttl", &ttl)) { + if (!strcmp(ttl, "loose")) { + ttlval = 1; + } else if (!strcmp(ttl, "skip")) { + ttlval = 2; + } else { + json_error(ctx, "Invalid osf ttl option '%s'.", ttl); + return NULL; + } + } + if (!strcmp(key, "name")) - return osf_expr_alloc(int_loc, ttl); + return osf_expr_alloc(int_loc, ttlval); json_error(ctx, "Invalid osf key value."); return NULL; diff --git a/tests/py/inet/osf.t.json b/tests/py/inet/osf.t.json index 45335cab30c0b..452f3023585b3 100644 --- a/tests/py/inet/osf.t.json +++ b/tests/py/inet/osf.t.json @@ -4,7 +4,6 @@ "match": { "left": { "osf": { - "ttl": 0, "key": "name" } }, @@ -14,13 +13,44 @@ } ] +# osf ttl loose name "Linux" +[ + { + "match": { + "left": { + "osf": { + "key": "name", + "ttl": "loose" + } + }, + "op": "==", + "right": "Linux" + } + } +] + +# osf ttl skip name "Linux" +[ + { + "match": { + "left": { + "osf": { + "key": "name", + "ttl": "skip" + } + }, + "op": "==", + "right": "Linux" + } + } +] + # osf name { "Windows", "MacOs" } [ { "match": { "left": { "osf": { - "ttl": 0, "key": "name" } }, @@ -60,7 +90,6 @@ }, "key": { "osf": { - "ttl": 0, "key": "name" } } -- 2.19.0