Add support for ttl option in "osf" expression. Example: table ip foo { chain bar { type filter hook input priority filter; policy accept; osf ttl skip name "Linux" } } Signed-off-by: Fernando Fernandez Mancera <ffmancera@xxxxxxxxxx> --- v1:initial patch v2:use "ttl-global, ttl-nocheck.." instead of "1, 2.." v3:better names for ttl options, add json and tests/py support All is working properly. --- include/expression.h | 4 ++ include/linux/netfilter/nf_tables.h | 2 + include/osf.h | 2 +- src/json.c | 2 +- src/netlink_delinearize.c | 5 ++- src/netlink_linearize.c | 1 + src/osf.c | 26 ++++++++++- src/parser_bison.y | 19 +++++++- src/parser_json.c | 5 ++- tests/py/inet/osf.t | 3 ++ tests/py/inet/osf.t.json | 3 ++ tests/py/inet/osf.t.payload | 68 ++++++++++++++++++++++++++++- 12 files changed, 129 insertions(+), 11 deletions(-) diff --git a/include/expression.h b/include/expression.h index d6977c3..f018c95 100644 --- a/include/expression.h +++ b/include/expression.h @@ -345,6 +345,10 @@ struct expr { uint8_t direction; uint8_t spnum; } xfrm; + struct { + /* EXPR_OSF */ + uint8_t ttl; + } osf; }; }; diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h index 4e28598..1d13ad3 100644 --- a/include/linux/netfilter/nf_tables.h +++ b/include/linux/netfilter/nf_tables.h @@ -939,10 +939,12 @@ enum nft_socket_keys { * enum nft_osf_attributes - nf_tables osf expression netlink attributes * * @NFTA_OSF_DREG: destination register (NLA_U32: nft_registers) + * @NFTA_OSF_TTL: Value of the TTL osf option (NLA_U8) */ enum nft_osf_attributes { NFTA_OSF_UNSPEC, NFTA_OSF_DREG, + NFTA_OSF_TTL, __NFTA_OSF_MAX }; #define NFT_OSF_MAX (__NFTA_OSF_MAX - 1) diff --git a/include/osf.h b/include/osf.h index 54cdd4a..23ea34d 100644 --- a/include/osf.h +++ b/include/osf.h @@ -1,7 +1,7 @@ #ifndef NFTABLES_OSF_H #define NFTABLES_OSF_H -struct expr *osf_expr_alloc(const struct location *loc); +struct expr *osf_expr_alloc(const struct location *loc, const uint8_t ttl); extern int nfnl_osf_load_fingerprints(struct netlink_ctx *ctx, int del); diff --git a/src/json.c b/src/json.c index 1cde270..cea9f19 100644 --- a/src/json.c +++ b/src/json.c @@ -857,7 +857,7 @@ 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:s}}", "osf", "key", "name"); + return json_pack("{s:{s:i, s:s}}", "osf", "ttl", expr->osf.ttl, "key", "name"); } json_t *xfrm_expr_json(const struct expr *expr, struct output_ctx *octx) diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c index cd05885..84948db 100644 --- a/src/netlink_delinearize.c +++ b/src/netlink_delinearize.c @@ -655,8 +655,11 @@ static void netlink_parse_osf(struct netlink_parse_ctx *ctx, { enum nft_registers dreg; struct expr *expr; + uint8_t ttl; + + ttl = nftnl_expr_get_u8(nle, NFTNL_EXPR_OSF_TTL); + expr = osf_expr_alloc(loc, ttl); - expr = osf_expr_alloc(loc); dreg = netlink_parse_register(nle, NFTNL_EXPR_OSF_DREG); netlink_set_register(ctx, dreg, expr); } diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c index 0ac51bd..0c8f5fe 100644 --- a/src/netlink_linearize.c +++ b/src/netlink_linearize.c @@ -227,6 +227,7 @@ static void netlink_gen_osf(struct netlink_linearize_ctx *ctx, nle = alloc_nft_expr("osf"); netlink_put_register(nle, NFTNL_EXPR_OSF_DREG, dreg); + nftnl_expr_set_u8(nle, NFTNL_EXPR_OSF_TTL, expr->osf.ttl); nftnl_rule_add_expr(ctx->nlr, nle); } diff --git a/src/osf.c b/src/osf.c index 85c9573..436f34b 100644 --- a/src/osf.c +++ b/src/osf.c @@ -5,13 +5,32 @@ #include <osf.h> #include <json.h> +static const char *osf_ttl_int_to_str(const uint8_t ttl) +{ + if (ttl == 1) + return "ttl loose "; + else if (ttl == 2) + return "ttl skip "; + + return ""; +} + static void osf_expr_print(const struct expr *expr, struct output_ctx *octx) { - nft_print(octx, "osf name"); + const char *ttl_str; + + ttl_str = osf_ttl_int_to_str(expr->osf.ttl); + nft_print(octx, "osf %sname", ttl_str); } static void osf_expr_clone(struct expr *new, const struct expr *expr) { + new->osf.ttl = expr->osf.ttl; +} + +static bool osf_expr_cmp(const struct expr *e1, const struct expr *e2) +{ + return e1->osf.ttl == e2->osf.ttl; } static const struct expr_ops osf_expr_ops = { @@ -19,10 +38,11 @@ static const struct expr_ops osf_expr_ops = { .name = "osf", .print = osf_expr_print, .clone = osf_expr_clone, + .cmp = osf_expr_cmp, .json = osf_expr_json, }; -struct expr *osf_expr_alloc(const struct location *loc) +struct expr *osf_expr_alloc(const struct location *loc, const uint8_t ttl) { unsigned int len = NFT_OSF_MAXGENRELEN * BITS_PER_BYTE; const struct datatype *type = &string_type; @@ -31,5 +51,7 @@ struct expr *osf_expr_alloc(const struct location *loc) expr = expr_alloc(loc, &osf_expr_ops, type, BYTEORDER_HOST_ENDIAN, len); + expr->osf.ttl = ttl; + return expr; } diff --git a/src/parser_bison.y b/src/parser_bison.y index 947a3cd..fec520a 100644 --- a/src/parser_bison.y +++ b/src/parser_bison.y @@ -15,12 +15,14 @@ #include <inttypes.h> #include <syslog.h> #include <netinet/ip.h> +#include <netinet/tcp.h> #include <netinet/if_ether.h> #include <linux/netfilter.h> #include <linux/netfilter/nf_tables.h> #include <linux/netfilter/nf_conntrack_tuple_common.h> #include <linux/netfilter/nf_nat.h> #include <linux/netfilter/nf_log.h> +#include <linux/netfilter/nfnetlink_osf.h> #include <linux/xfrm.h> #include <netinet/ip_icmp.h> #include <netinet/icmp6.h> @@ -743,6 +745,7 @@ int nft_lex(void *, void *, void *); %type <val> fib_tuple fib_result fib_flag %type <expr> osf_expr +%type <val> osf_ttl %destructor { expr_free($$); } osf_expr %type <val> markup_format @@ -3176,9 +3179,21 @@ fib_tuple : fib_flag DOT fib_tuple | fib_flag ; -osf_expr : OSF NAME +osf_expr : OSF osf_ttl NAME { - $$ = osf_expr_alloc(&@$); + $$ = osf_expr_alloc(&@$, $2); + } + ; + +osf_ttl : /* empty */ { $$ = NF_OSF_TTL_TRUE; } + | TTL STRING + { + if (!strcmp($2, "loose")) + $$ = NF_OSF_TTL_LESS; + else if (!strcmp($2, "skip")) + $$ = NF_OSF_TTL_NOCHECK; + else + $$ = 3; } ; diff --git a/src/parser_json.c b/src/parser_json.c index 7047c00..fc0dc9a 100644 --- a/src/parser_json.c +++ b/src/parser_json.c @@ -376,12 +376,13 @@ static struct expr *json_parse_osf_expr(struct json_ctx *ctx, const char *type, json_t *root) { const char *key; + uint8_t ttl; - if (json_unpack_err(ctx, root, "{s:s}", "key", &key)) + if (json_unpack_err(ctx, root, "{s:i, s:s}", "ttl", ttl,"key", &key)) return NULL; if (!strcmp(key, "name")) - return osf_expr_alloc(int_loc); + return osf_expr_alloc(int_loc, ttl); json_error(ctx, "Invalid osf key value."); return NULL; diff --git a/tests/py/inet/osf.t b/tests/py/inet/osf.t index bccfc75..fd5d9ed 100644 --- a/tests/py/inet/osf.t +++ b/tests/py/inet/osf.t @@ -5,6 +5,9 @@ *inet;osfinet;osfchain osf name "Linux";ok +osf ttl loose name "Linux";ok +osf ttl skip name "Linux";ok +osf ttl nottl name "Linux";fail osf name "morethansixteenbytes";fail osf name ;fail osf name { "Windows", "MacOs" };ok diff --git a/tests/py/inet/osf.t.json b/tests/py/inet/osf.t.json index 4bb413c..45335ca 100644 --- a/tests/py/inet/osf.t.json +++ b/tests/py/inet/osf.t.json @@ -4,6 +4,7 @@ "match": { "left": { "osf": { + "ttl": 0, "key": "name" } }, @@ -19,6 +20,7 @@ "match": { "left": { "osf": { + "ttl": 0, "key": "name" } }, @@ -58,6 +60,7 @@ }, "key": { "osf": { + "ttl": 0, "key": "name" } } diff --git a/tests/py/inet/osf.t.payload b/tests/py/inet/osf.t.payload index 850ca29..9b8f0bc 100644 --- a/tests/py/inet/osf.t.payload +++ b/tests/py/inet/osf.t.payload @@ -13,19 +13,83 @@ inet osfinet osfchain [ osf dreg 1 ] [ cmp eq reg 1 0x756e694c 0x00000078 0x00000000 0x00000000 ] +# osf ttl loose name "Linux" +ip osfip osfchain + [ osf dreg 1 ] + [ cmp eq reg 1 0x756e694c 0x00000078 0x00000000 0x00000000 ] + +# osf ttl loose name "Linux" +ip6 osfip6 osfchain + [ osf dreg 1 ] + [ cmp eq reg 1 0x756e694c 0x00000078 0x00000000 0x00000000 ] + +# osf ttl loose name "Linux" +inet osfinet osfchain + [ osf dreg 1 ] + [ cmp eq reg 1 0x756e694c 0x00000078 0x00000000 0x00000000 ] + +# osf ttl skip name "Linux" +ip osfip osfchain + [ osf dreg 1 ] + [ cmp eq reg 1 0x756e694c 0x00000078 0x00000000 0x00000000 ] + +# osf ttl skip name "Linux" +ip6 osfip6 osfchain + [ osf dreg 1 ] + [ cmp eq reg 1 0x756e694c 0x00000078 0x00000000 0x00000000 ] + +# osf ttl skip name "Linux" +inet osfinet osfchain + [ osf dreg 1 ] + [ cmp eq reg 1 0x756e694c 0x00000078 0x00000000 0x00000000 ] + +# osf name { "Windows", "MacOs" } +__set%d osfip 3 size 2 +__set%d osfip 0 + element 646e6957 0073776f 00000000 00000000 : 0 [end] element 4f63614d 00000073 00000000 00000000 : 0 [end] +ip osfip osfchain + [ osf dreg 1 ] + [ lookup reg 1 set __set%d ] + +# osf name { "Windows", "MacOs" } +__set%d osfip6 3 size 2 +__set%d osfip6 0 + element 646e6957 0073776f 00000000 00000000 : 0 [end] element 4f63614d 00000073 00000000 00000000 : 0 [end] +ip6 osfip6 osfchain + [ osf dreg 1 ] + [ lookup reg 1 set __set%d ] + # osf name { "Windows", "MacOs" } __set%d osfinet 3 size 2 __set%d osfinet 0 element 646e6957 0073776f 00000000 00000000 : 0 [end] element 4f63614d 00000073 00000000 00000000 : 0 [end] -inet osfinet osfchain +inet osfinet osfchain [ osf dreg 1 ] [ lookup reg 1 set __set%d ] # ct mark set osf name map { "Windows" : 0x00000001, "MacOs" : 0x00000002 } __map%d osfip b size 2 __map%d osfip 0 - element 646e6957 0073776f 00000000 00000000 : 00000001 0 [end] element 4f63614d 00000073 00000000 00000000 : 00000002 0 [end] + element 646e6957 0073776f 00000000 00000000 : 00000001 0 [end] element 4f63614d 00000073 00000000 00000000 : 00000002 0 [end] ip osfip osfchain [ osf dreg 1 ] [ lookup reg 1 set __map%d dreg 1 ] [ ct set mark with reg 1 ] + +# ct mark set osf name map { "Windows" : 0x00000001, "MacOs" : 0x00000002 } +__map%d osfip6 b size 2 +__map%d osfip6 0 + element 646e6957 0073776f 00000000 00000000 : 00000001 0 [end] element 4f63614d 00000073 00000000 00000000 : 00000002 0 [end] +ip6 osfip6 osfchain + [ osf dreg 1 ] + [ lookup reg 1 set __map%d dreg 1 ] + [ ct set mark with reg 1 ] + +# ct mark set osf name map { "Windows" : 0x00000001, "MacOs" : 0x00000002 } +__map%d osfinet b size 2 +__map%d osfinet 0 + element 646e6957 0073776f 00000000 00000000 : 00000001 0 [end] element 4f63614d 00000073 00000000 00000000 : 00000002 0 [end] +inet osfinet osfchain + [ osf dreg 1 ] + [ lookup reg 1 set __map%d dreg 1 ] + [ ct set mark with reg 1 ] -- 2.19.1