summaryrefslogtreecommitdiffstats
path: root/src/evaluate.c
diff options
context:
space:
mode:
authorPablo Neira Ayuso <pablo@netfilter.org>2020-07-04 02:43:44 +0200
committerPablo Neira Ayuso <pablo@netfilter.org>2020-07-15 21:56:29 +0200
commitc330152b7f7779f15dba3e0862bf5616e7cb3eab (patch)
tree49c9ab5d837ab99a23e15399acb7ea610606ecfc /src/evaluate.c
parent1cba7a5e5e96dd920271823125b45e182f22ec82 (diff)
src: support for implicit chain bindings
This patch allows you to group rules in a subchain, e.g. table inet x { chain y { type filter hook input priority 0; tcp dport 22 jump { ip saddr { 127.0.0.0/8, 172.23.0.0/16, 192.168.13.0/24 } accept ip6 saddr ::1/128 accept; } } } This also supports for the `goto' chain verdict. This patch adds a new chain binding list to avoid a chain list lookup from the delinearize path for the usual chains. This can be simplified later on with a single hashtable per table for all chains. From the shell, you have to use the explicit separator ';', in bash you have to escape this: # nft add rule inet x y tcp dport 80 jump { ip saddr 127.0.0.1 accept\; ip6 saddr ::1 accept \; } Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'src/evaluate.c')
-rw-r--r--src/evaluate.c61
1 files changed, 60 insertions, 1 deletions
diff --git a/src/evaluate.c b/src/evaluate.c
index d3368bac..f12c88a0 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -3098,6 +3098,63 @@ static int stmt_evaluate_synproxy(struct eval_ctx *ctx, struct stmt *stmt)
return 0;
}
+static int rule_evaluate(struct eval_ctx *ctx, struct rule *rule,
+ enum cmd_ops op);
+
+static int stmt_evaluate_chain(struct eval_ctx *ctx, struct stmt *stmt)
+{
+ struct chain *chain = stmt->chain.chain;
+ struct cmd *cmd;
+
+ chain->flags |= CHAIN_F_BINDING;
+
+ if (ctx->table != NULL) {
+ list_add_tail(&chain->list, &ctx->table->chains);
+ } else {
+ struct rule *rule, *next;
+ struct handle h;
+
+ memset(&h, 0, sizeof(h));
+ handle_merge(&h, &chain->handle);
+ h.family = ctx->rule->handle.family;
+ xfree(h.table.name);
+ h.table.name = xstrdup(ctx->rule->handle.table.name);
+ h.chain.location = stmt->location;
+ h.chain_id = chain->handle.chain_id;
+
+ cmd = cmd_alloc(CMD_ADD, CMD_OBJ_CHAIN, &h, &stmt->location,
+ chain);
+ cmd->location = stmt->location;
+ list_add_tail(&cmd->list, &ctx->cmd->list);
+ h.chain_id = chain->handle.chain_id;
+
+ list_for_each_entry_safe(rule, next, &chain->rules, list) {
+ struct eval_ctx rule_ctx = {
+ .nft = ctx->nft,
+ .msgs = ctx->msgs,
+ };
+ struct handle h2 = {};
+
+ handle_merge(&rule->handle, &ctx->rule->handle);
+ xfree(rule->handle.table.name);
+ rule->handle.table.name = xstrdup(ctx->rule->handle.table.name);
+ xfree(rule->handle.chain.name);
+ rule->handle.chain.name = NULL;
+ rule->handle.chain_id = chain->handle.chain_id;
+ if (rule_evaluate(&rule_ctx, rule, CMD_INVALID) < 0)
+ return -1;
+
+ handle_merge(&h2, &rule->handle);
+ cmd = cmd_alloc(CMD_ADD, CMD_OBJ_RULE, &h2,
+ &rule->location, rule);
+ list_add_tail(&cmd->list, &ctx->cmd->list);
+ list_del(&rule->list);
+ }
+ }
+
+ return 0;
+}
+
static int stmt_evaluate_dup(struct eval_ctx *ctx, struct stmt *stmt)
{
int err;
@@ -3490,6 +3547,8 @@ int stmt_evaluate(struct eval_ctx *ctx, struct stmt *stmt)
return stmt_evaluate_map(ctx, stmt);
case STMT_SYNPROXY:
return stmt_evaluate_synproxy(ctx, stmt);
+ case STMT_CHAIN:
+ return stmt_evaluate_chain(ctx, stmt);
default:
BUG("unknown statement type %s\n", stmt->ops->name);
}
@@ -3879,7 +3938,7 @@ static int chain_evaluate(struct eval_ctx *ctx, struct chain *chain)
chain_add_hash(chain, table);
}
return 0;
- } else {
+ } else if (!(chain->flags & CHAIN_F_BINDING)) {
if (chain_lookup(table, &chain->handle) == NULL)
chain_add_hash(chain_get(chain), table);
}