summaryrefslogtreecommitdiffstats
path: root/src/rule.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/rule.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/rule.c')
-rw-r--r--src/rule.c49
1 files changed, 45 insertions, 4 deletions
diff --git a/src/rule.c b/src/rule.c
index 21a52157..fa186140 100644
--- a/src/rule.c
+++ b/src/rule.c
@@ -177,7 +177,10 @@ static int cache_init_objects(struct netlink_ctx *ctx, unsigned int flags)
ret = netlink_list_chains(ctx, &table->handle);
if (ret < 0)
return -1;
+
list_splice_tail_init(&ctx->list, &table->chains);
+ list_splice_tail_init(&ctx->list_bindings,
+ &table->chain_bindings);
}
if (flags & NFT_CACHE_FLOWTABLE_BIT) {
ret = netlink_list_flowtables(ctx, &table->handle);
@@ -196,6 +199,9 @@ static int cache_init_objects(struct netlink_ctx *ctx, unsigned int flags)
ret = netlink_list_rules(ctx, &table->handle);
list_for_each_entry_safe(rule, nrule, &ctx->list, list) {
chain = chain_lookup(table, &rule->handle);
+ if (!chain)
+ chain = chain_binding_lookup(table,
+ rule->handle.chain.name);
list_move_tail(&rule->list, &chain->rules);
}
if (ret < 0)
@@ -245,6 +251,7 @@ int cache_update(struct nft_ctx *nft, unsigned int flags, struct list_head *msgs
{
struct netlink_ctx ctx = {
.list = LIST_HEAD_INIT(ctx.list),
+ .list_bindings = LIST_HEAD_INIT(ctx.list_bindings),
.nft = nft,
.msgs = msgs,
};
@@ -858,12 +865,16 @@ const char *chain_hookname_lookup(const char *name)
return NULL;
}
+/* internal ID to uniquely identify a set in the batch */
+static uint32_t chain_id;
+
struct chain *chain_alloc(const char *name)
{
struct chain *chain;
chain = xzalloc(sizeof(*chain));
chain->refcnt = 1;
+ chain->handle.chain_id = ++chain_id;
init_list_head(&chain->rules);
init_list_head(&chain->scope.symbols);
if (name != NULL)
@@ -916,6 +927,18 @@ struct chain *chain_lookup(const struct table *table, const struct handle *h)
return NULL;
}
+struct chain *chain_binding_lookup(const struct table *table,
+ const char *chain_name)
+{
+ struct chain *chain;
+
+ list_for_each_entry(chain, &table->chain_bindings, list) {
+ if (!strcmp(chain->handle.chain.name, chain_name))
+ return chain;
+ }
+ return NULL;
+}
+
struct chain *chain_lookup_fuzzy(const struct handle *h,
const struct nft_cache *cache,
const struct table **t)
@@ -1175,6 +1198,9 @@ static void chain_print_declaration(const struct chain *chain,
char priobuf[STD_PRIO_BUFSIZE];
int policy, i;
+ if (chain->flags & CHAIN_F_BINDING)
+ return;
+
nft_print(octx, "\tchain %s {", chain->handle.chain.name);
if (nft_output_handle(octx))
nft_print(octx, " # handle %" PRIu64, chain->handle.handle.id);
@@ -1210,17 +1236,22 @@ static void chain_print_declaration(const struct chain *chain,
}
}
-static void chain_print(const struct chain *chain, struct output_ctx *octx)
+void chain_rules_print(const struct chain *chain, struct output_ctx *octx,
+ const char *indent)
{
struct rule *rule;
- chain_print_declaration(chain, octx);
-
list_for_each_entry(rule, &chain->rules, list) {
- nft_print(octx, "\t\t");
+ nft_print(octx, "\t\t%s", indent ? : "");
rule_print(rule, octx);
nft_print(octx, "\n");
}
+}
+
+static void chain_print(const struct chain *chain, struct output_ctx *octx)
+{
+ chain_print_declaration(chain, octx);
+ chain_rules_print(chain, octx, NULL);
nft_print(octx, "\t}\n");
}
@@ -1255,6 +1286,7 @@ struct table *table_alloc(void)
init_list_head(&table->sets);
init_list_head(&table->objs);
init_list_head(&table->flowtables);
+ init_list_head(&table->chain_bindings);
init_list_head(&table->scope.symbols);
table->refcnt = 1;
@@ -1272,6 +1304,8 @@ void table_free(struct table *table)
return;
list_for_each_entry_safe(chain, next, &table->chains, list)
chain_free(chain);
+ list_for_each_entry_safe(chain, next, &table->chain_bindings, list)
+ chain_free(chain);
list_for_each_entry_safe(set, nset, &table->sets, list)
set_free(set);
list_for_each_entry_safe(ft, nft, &table->flowtables, list)
@@ -1437,6 +1471,7 @@ void nft_cmd_expand(struct cmd *cmd)
list_for_each_entry(chain, &table->chains, list) {
memset(&h, 0, sizeof(h));
handle_merge(&h, &chain->handle);
+ h.chain_id = chain->handle.chain_id;
new = cmd_alloc(CMD_ADD, CMD_OBJ_CHAIN, &h,
&chain->location, chain_get(chain));
list_add_tail(&new->list, &new_cmds);
@@ -1469,6 +1504,12 @@ void nft_cmd_expand(struct cmd *cmd)
list_for_each_entry(rule, &chain->rules, list) {
memset(&h, 0, sizeof(h));
handle_merge(&h, &rule->handle);
+ if (chain->flags & CHAIN_F_BINDING) {
+ rule->handle.chain_id =
+ chain->handle.chain_id;
+ rule->handle.chain.location =
+ chain->location;
+ }
new = cmd_alloc(CMD_ADD, CMD_OBJ_RULE, &h,
&rule->location,
rule_get(rule));