]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
src: add stateful object reference expression
authorPablo Neira Ayuso <pablo@netfilter.org>
Sun, 27 Nov 2016 22:34:57 +0000 (23:34 +0100)
committerPablo Neira Ayuso <pablo@netfilter.org>
Tue, 3 Jan 2017 13:21:53 +0000 (14:21 +0100)
This patch adds a new objref statement to refer to existing stateful
objects from rules, eg.

 # nft add rule filter input counter name test counter

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
include/statement.h
src/evaluate.c
src/netlink_delinearize.c
src/netlink_linearize.c
src/parser_bison.y
src/scanner.l
src/statement.c

index 9d0f601f98a296a78169c14543486bc7beb4d9d9..8f874c881bd9a98512d5094eae88c3ee94c0bf2b 100644 (file)
@@ -10,6 +10,13 @@ extern struct stmt *expr_stmt_alloc(const struct location *loc,
 extern struct stmt *verdict_stmt_alloc(const struct location *loc,
                                       struct expr *expr);
 
+struct objref_stmt {
+       uint32_t                type;
+       struct expr             *expr;
+};
+
+struct stmt *objref_stmt_alloc(const struct location *loc);
+
 struct counter_stmt {
        uint64_t                packets;
        uint64_t                bytes;
@@ -212,6 +219,7 @@ extern struct stmt *xt_stmt_alloc(const struct location *loc);
  * @STMT_XT:           XT statement
  * @STMT_QUOTA:                quota statement
  * @STMT_NOTRACK:      notrack statement
+ * @STMT_OBJREF:       stateful object reference statement
  */
 enum stmt_types {
        STMT_INVALID,
@@ -235,6 +243,7 @@ enum stmt_types {
        STMT_XT,
        STMT_QUOTA,
        STMT_NOTRACK,
+       STMT_OBJREF,
 };
 
 /**
@@ -292,6 +301,7 @@ struct stmt {
                struct dup_stmt         dup;
                struct fwd_stmt         fwd;
                struct xt_stmt          xt;
+               struct objref_stmt      objref;
        };
 };
 
index cedf259fcba9ef61a14f59bc0da4d0eb7186c09b..b868f1bc283aca517ec3aacd2c16cc31094346f5 100644 (file)
@@ -2464,6 +2464,20 @@ static int stmt_evaluate_set(struct eval_ctx *ctx, struct stmt *stmt)
        return 0;
 }
 
+static int stmt_evaluate_objref(struct eval_ctx *ctx, struct stmt *stmt)
+{
+       if (stmt_evaluate_arg(ctx, stmt,
+                             &string_type, NFT_OBJ_MAXNAMELEN * BITS_PER_BYTE,
+                             &stmt->objref.expr) < 0)
+               return -1;
+
+       if (!expr_is_constant(stmt->objref.expr))
+               return expr_error(ctx->msgs, stmt->objref.expr,
+                                 "Counter expression must be constant");
+
+       return 0;
+}
+
 int stmt_evaluate(struct eval_ctx *ctx, struct stmt *stmt)
 {
 #ifdef DEBUG
@@ -2511,6 +2525,8 @@ int stmt_evaluate(struct eval_ctx *ctx, struct stmt *stmt)
                return stmt_evaluate_fwd(ctx, stmt);
        case STMT_SET:
                return stmt_evaluate_set(ctx, stmt);
+       case STMT_OBJREF:
+               return stmt_evaluate_objref(ctx, stmt);
        default:
                BUG("unknown statement type %s\n", stmt->ops->name);
        }
index 9a16926e381730af126b4e39729b6f673497302f..90fb9e6707514eaefa8682b157b67b1bdb50d444 100644 (file)
@@ -1125,6 +1125,35 @@ static void netlink_parse_dynset(struct netlink_parse_ctx *ctx,
        ctx->stmt = stmt;
 }
 
+static void netlink_parse_objref(struct netlink_parse_ctx *ctx,
+                                const struct location *loc,
+                                const struct nftnl_expr *nle)
+{
+       uint32_t type = nftnl_expr_get_u32(nle, NFTNL_EXPR_OBJREF_IMM_TYPE);
+       struct expr *expr;
+       struct stmt *stmt;
+
+       if (nftnl_expr_is_set(nle, NFTNL_EXPR_OBJREF_IMM_NAME)) {
+               struct nft_data_delinearize nld;
+
+               type = nftnl_expr_get_u32(nle, NFTNL_EXPR_OBJREF_IMM_TYPE);
+               nld.value = nftnl_expr_get(nle, NFTNL_EXPR_OBJREF_IMM_NAME,
+                                          &nld.len);
+               expr = netlink_alloc_value(&netlink_location, &nld);
+               expr->dtype = &string_type;
+               expr->byteorder = BYTEORDER_HOST_ENDIAN;
+       } else {
+               netlink_error(ctx, loc, "unknown objref expression type %u",
+                             type);
+               return;
+       }
+
+       stmt = objref_stmt_alloc(loc);
+       stmt->objref.type = type;
+       stmt->objref.expr = expr;
+       ctx->stmt = stmt;
+}
+
 static const struct {
        const char      *name;
        void            (*parse)(struct netlink_parse_ctx *ctx,
@@ -1156,6 +1185,7 @@ static const struct {
        { .name = "fwd",        .parse = netlink_parse_fwd },
        { .name = "target",     .parse = netlink_parse_target },
        { .name = "match",      .parse = netlink_parse_match },
+       { .name = "objref",     .parse = netlink_parse_objref },
        { .name = "quota",      .parse = netlink_parse_quota },
        { .name = "numgen",     .parse = netlink_parse_numgen },
        { .name = "hash",       .parse = netlink_parse_hash },
@@ -2164,6 +2194,9 @@ static void rule_parse_postprocess(struct netlink_parse_ctx *ctx, struct rule *r
                case STMT_XT:
                        stmt_xt_postprocess(&rctx, stmt, rule);
                        break;
+               case STMT_OBJREF:
+                       expr_postprocess(&rctx, &stmt->objref.expr);
+                       break;
                default:
                        break;
                }
index 144068d233786663f2d4a1421dded4be0cb0b756..c9488b3212bc15cf70045177eda1d8b327e42694 100644 (file)
@@ -689,6 +689,20 @@ static void netlink_gen_expr(struct netlink_linearize_ctx *ctx,
        }
 }
 
+static void netlink_gen_objref_stmt(struct netlink_linearize_ctx *ctx,
+                                   const struct stmt *stmt)
+{
+       struct nft_data_linearize nld;
+       struct nftnl_expr *nle;
+
+       nle = alloc_nft_expr("objref");
+       netlink_gen_data(stmt->objref.expr, &nld);
+       nftnl_expr_set(nle, NFTNL_EXPR_OBJREF_IMM_NAME, nld.value, nld.len);
+       nftnl_expr_set_u32(nle, NFTNL_EXPR_OBJREF_IMM_TYPE, stmt->objref.type);
+
+       nftnl_rule_add_expr(ctx->nlr, nle);
+}
+
 static struct nftnl_expr *
 netlink_gen_counter_stmt(struct netlink_linearize_ctx *ctx,
                         const struct stmt *stmt)
@@ -1225,6 +1239,8 @@ static void netlink_gen_stmt(struct netlink_linearize_ctx *ctx,
                break;
        case STMT_NOTRACK:
                return netlink_gen_notrack_stmt(ctx, stmt);
+       case STMT_OBJREF:
+               return netlink_gen_objref_stmt(ctx, stmt);
        default:
                BUG("unknown statement type %s\n", stmt->ops->name);
        }
index 5b829a243128bc2154f0719efb8f6d1168224274..795b0ee210a3d45d0a3f79f6af208d60e7c717a0 100644 (file)
@@ -365,6 +365,7 @@ static void location_update(struct location *loc, struct location *rhs, int n)
 %token LABEL                   "label"
 
 %token COUNTER                 "counter"
+%token NAME                    "name"
 %token PACKETS                 "packets"
 %token BYTES                   "bytes"
 
@@ -1623,6 +1624,12 @@ counter_stmt_alloc       :       COUNTER
                        {
                                $$ = counter_stmt_alloc(&@$);
                        }
+                       |       COUNTER         NAME    stmt_expr
+                       {
+                               $$ = objref_stmt_alloc(&@$);
+                               $$->objref.type = NFT_OBJECT_COUNTER;
+                               $$->objref.expr = $3;
+                       }
                        ;
 
 counter_args           :       counter_arg
@@ -1823,6 +1830,12 @@ quota_stmt               :       QUOTA   quota_mode NUM quota_unit quota_used
                                $$->quota.used = $5;
                                $$->quota.flags = $2;
                        }
+                       |       QUOTA   NAME    stmt_expr
+                       {
+                               $$ = objref_stmt_alloc(&@$);
+                               $$->objref.type = NFT_OBJECT_QUOTA;
+                               $$->objref.expr = $3;
+                       }
                        ;
 
 limit_mode             :       OVER                            { $$ = NFT_LIMIT_F_INV; }
index 1aa2e96b9f647367d40403820603389eb7b9ed34..69406bd0164e0f6ec9ea4de6a5be4c17fd5888fc 100644 (file)
@@ -291,6 +291,7 @@ addrstring  ({macaddr}|{ip4addr}|{ip6addr})
 "flow"                 { return FLOW; }
 
 "counter"              { return COUNTER; }
+"name"                 { return NAME; }
 "packets"              { return PACKETS; }
 "bytes"                        { return BYTES; }
 
index fbd78aafe69a32237546a906c2aecc7a985e843e..24a53ee1b0fc8709b1923de3d518e2a0c842c48c 100644 (file)
@@ -161,6 +161,39 @@ struct stmt *counter_stmt_alloc(const struct location *loc)
        return stmt;
 }
 
+static const char *objref_type[NFT_OBJECT_MAX + 1] = {
+       [NFT_OBJECT_COUNTER]    = "counter",
+       [NFT_OBJECT_QUOTA]      = "quota",
+};
+
+static const char *objref_type_name(uint32_t type)
+{
+       if (type > NFT_OBJECT_MAX)
+               return "unknown";
+
+       return objref_type[type];
+}
+
+static void objref_stmt_print(const struct stmt *stmt)
+{
+       printf("%s name ", objref_type_name(stmt->objref.type));
+       expr_print(stmt->objref.expr);
+}
+
+static const struct stmt_ops objref_stmt_ops = {
+       .type           = STMT_OBJREF,
+       .name           = "objref",
+       .print          = objref_stmt_print,
+};
+
+struct stmt *objref_stmt_alloc(const struct location *loc)
+{
+       struct stmt *stmt;
+
+       stmt = stmt_alloc(loc, &objref_stmt_ops);
+       return stmt;
+}
+
 static const char *syslog_level[LOG_DEBUG + 1] = {
        [LOG_EMERG]     = "emerg",
        [LOG_ALERT]     = "alert",