Add support for version fingerprint in "osf" expression. Example:

table ip foo {
        chain bar {
                type filter hook input priority filter; policy accept;
                osf ttl skip name "Linux"
                osf ttl skip version "Linux:4.20"
        }
}

Signed-off-by: Fernando Fernandez Mancera <[email protected]>
---
 include/expression.h                |  1 +
 include/linux/netfilter/nf_tables.h |  6 ++++++
 include/osf.h                       |  3 ++-
 src/netlink_delinearize.c           |  4 +++-
 src/netlink_linearize.c             |  1 +
 src/osf.c                           | 13 ++++++++++---
 src/parser_bison.y                  |  8 ++++++--
 7 files changed, 29 insertions(+), 7 deletions(-)

diff --git a/include/expression.h b/include/expression.h
index 6d72f64..6416ac0 100644
--- a/include/expression.h
+++ b/include/expression.h
@@ -350,6 +350,7 @@ struct expr {
                struct {
                        /* EXPR_OSF */
                        uint8_t                 ttl;
+                       uint32_t                flags;
                } osf;
        };
 };
diff --git a/include/linux/netfilter/nf_tables.h 
b/include/linux/netfilter/nf_tables.h
index 37036be..09a7b9e 100644
--- a/include/linux/netfilter/nf_tables.h
+++ b/include/linux/netfilter/nf_tables.h
@@ -944,15 +944,21 @@ enum nft_socket_keys {
  *
  * @NFTA_OSF_DREG: destination register (NLA_U32: nft_registers)
  * @NFTA_OSF_TTL: Value of the TTL osf option (NLA_U8)
+ * @NFTA_OSF_FLAGS: flags (NLA_U32)
  */
 enum nft_osf_attributes {
        NFTA_OSF_UNSPEC,
        NFTA_OSF_DREG,
        NFTA_OSF_TTL,
+       NFTA_OSF_FLAGS,
        __NFTA_OSF_MAX
 };
 #define NFT_OSF_MAX            (__NFTA_OSF_MAX - 1)
 
+enum nft_osf_flags {
+       NFT_OSF_F_VERSION       = 1 << 0,       /* check fingerprint version */
+};
+
 /**
  * enum nft_ct_keys - nf_tables ct expression keys
  *
diff --git a/include/osf.h b/include/osf.h
index 23ea34d..8f6f584 100644
--- a/include/osf.h
+++ b/include/osf.h
@@ -1,7 +1,8 @@
 #ifndef NFTABLES_OSF_H
 #define NFTABLES_OSF_H
 
-struct expr *osf_expr_alloc(const struct location *loc, const uint8_t ttl);
+struct expr *osf_expr_alloc(const struct location *loc, const uint8_t ttl,
+                           const uint32_t flags);
 
 extern int nfnl_osf_load_fingerprints(struct netlink_ctx *ctx, int del);
 
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
index d0eaf5b..9a2d63d 100644
--- a/src/netlink_delinearize.c
+++ b/src/netlink_delinearize.c
@@ -655,10 +655,12 @@ static void netlink_parse_osf(struct netlink_parse_ctx 
*ctx,
 {
        enum nft_registers dreg;
        struct expr *expr;
+       uint32_t flags;
        uint8_t ttl;
 
        ttl = nftnl_expr_get_u8(nle, NFTNL_EXPR_OSF_TTL);
-       expr = osf_expr_alloc(loc, ttl);
+       flags = nftnl_expr_get_u32(nle, NFTNL_EXPR_OSF_FLAGS);
+       expr = osf_expr_alloc(loc, ttl, flags);
 
        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 61149bf..8df82d5 100644
--- a/src/netlink_linearize.c
+++ b/src/netlink_linearize.c
@@ -228,6 +228,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_expr_set_u32(nle, NFTNL_EXPR_OSF_FLAGS, expr->osf.flags);
        nftnl_rule_add_expr(ctx->nlr, nle);
 }
 
diff --git a/src/osf.c b/src/osf.c
index 9252934..f0c2239 100644
--- a/src/osf.c
+++ b/src/osf.c
@@ -19,17 +19,22 @@ static void osf_expr_print(const struct expr *expr, struct 
output_ctx *octx)
 {
        const char *ttl_str = osf_ttl_int_to_str(expr->osf.ttl);
 
-       nft_print(octx, "osf %sname", ttl_str);
+       if (expr->osf.flags & NFT_OSF_F_VERSION)
+               nft_print(octx, "osf %sversion", ttl_str);
+       else
+               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;
+       new->osf.flags = expr->osf.flags;
 }
 
 static bool osf_expr_cmp(const struct expr *e1, const struct expr *e2)
 {
-       return e1->osf.ttl == e2->osf.ttl;
+       return (e1->osf.ttl == e2->osf.ttl) &&
+              (e1->osf.flags == e2->osf.flags);
 }
 
 const struct expr_ops osf_expr_ops = {
@@ -41,7 +46,8 @@ const struct expr_ops osf_expr_ops = {
        .json           = osf_expr_json,
 };
 
-struct expr *osf_expr_alloc(const struct location *loc, const uint8_t ttl)
+struct expr *osf_expr_alloc(const struct location *loc, const uint8_t ttl,
+                           const uint32_t flags)
 {
        unsigned int len = NFT_OSF_MAXGENRELEN * BITS_PER_BYTE;
        const struct datatype *type = &string_type;
@@ -50,6 +56,7 @@ struct expr *osf_expr_alloc(const struct location *loc, const 
uint8_t ttl)
        expr = expr_alloc(loc, EXPR_OSF, type,
                          BYTEORDER_HOST_ENDIAN, len);
        expr->osf.ttl = ttl;
+       expr->osf.flags = flags;
 
        return expr;
 }
diff --git a/src/parser_bison.y b/src/parser_bison.y
index 65b3fb3..6e1bb88 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -3190,9 +3190,13 @@ fib_tuple                :       fib_flag        DOT     
fib_tuple
                        |       fib_flag
                        ;
 
-osf_expr               :       OSF     osf_ttl         NAME
+osf_expr               :       OSF     osf_ttl         HDRVERSION
                        {
-                               $$ = osf_expr_alloc(&@$, $2);
+                               $$ = osf_expr_alloc(&@$, $2, NFT_OSF_F_VERSION);
+                       }
+                       |       OSF     osf_ttl         NAME
+                       {
+                               $$ = osf_expr_alloc(&@$, $2, 0);
                        }
                        ;
 
-- 
2.20.1

Reply via email to