summaryrefslogtreecommitdiffstats
path: root/src/evaluate.c
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2016-04-27 12:29:50 +0100
committerPablo Neira Ayuso <pablo@netfilter.org>2016-05-13 19:30:29 +0200
commit3ed5e31f4a323d7f054b6120d05134195dc681f0 (patch)
tree5daa5afd681e9b3dbada6405659cd11cefc19554 /src/evaluate.c
parent9f3cce668b72c9ec9d9e0a6071d132a8f35d7b70 (diff)
src: add flow statement
The flow statement allows to instantiate per flow statements for user defined flows. This can so far be used for per flow accounting or limiting, similar to what the iptables hashlimit provides. Flows can be aged using the timeout option. Examples: # nft filter input flow ip saddr . tcp dport limit rate 10/second # nft filter input flow table acct iif . ip saddr timeout 60s counter Signed-off-by: Patrick McHardy <kaber@trash.net> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'src/evaluate.c')
-rw-r--r--src/evaluate.c37
1 files changed, 37 insertions, 0 deletions
diff --git a/src/evaluate.c b/src/evaluate.c
index 9d89d905..53f19b29 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -1638,6 +1638,41 @@ static int stmt_evaluate_payload(struct eval_ctx *ctx, struct stmt *stmt)
&stmt->payload.val);
}
+static int stmt_evaluate_flow(struct eval_ctx *ctx, struct stmt *stmt)
+{
+ struct expr *key, *set, *setref;
+
+ expr_set_context(&ctx->ectx, NULL, 0);
+ if (expr_evaluate(ctx, &stmt->flow.key) < 0)
+ return -1;
+ if (expr_is_constant(stmt->flow.key))
+ return expr_error(ctx->msgs, stmt->flow.key,
+ "Flow key expression can not be constant");
+ if (stmt->flow.key->comment)
+ return expr_error(ctx->msgs, stmt->flow.key,
+ "Flow key expression can not contain comments");
+
+ /* Declare an empty set */
+ key = stmt->flow.key;
+ set = set_expr_alloc(&key->location);
+ set->set_flags |= SET_F_EVAL;
+ if (key->timeout)
+ set->set_flags |= SET_F_TIMEOUT;
+
+ setref = implicit_set_declaration(ctx, stmt->flow.table ?: "__ft%d",
+ key->dtype, key->len, set);
+
+ stmt->flow.set = setref;
+
+ if (stmt_evaluate(ctx, stmt->flow.stmt) < 0)
+ return -1;
+ if (!(stmt->flow.stmt->flags & STMT_F_STATEFUL))
+ return stmt_binary_error(ctx, stmt->flow.stmt, stmt,
+ "Per-flow statement must be stateful");
+
+ return 0;
+}
+
static int stmt_evaluate_meta(struct eval_ctx *ctx, struct stmt *stmt)
{
return stmt_evaluate_arg(ctx, stmt,
@@ -2257,6 +2292,8 @@ int stmt_evaluate(struct eval_ctx *ctx, struct stmt *stmt)
return stmt_evaluate_verdict(ctx, stmt);
case STMT_PAYLOAD:
return stmt_evaluate_payload(ctx, stmt);
+ case STMT_FLOW:
+ return stmt_evaluate_flow(ctx, stmt);
case STMT_META:
return stmt_evaluate_meta(ctx, stmt);
case STMT_CT: