This allows all possible combinations to work: nft add chain filter input { type filter hook input priority 0 \; } nft add chain filter input { priority 0 type filter hook input \; } Wrt. error reporting, this also improves interaction with humans a bit: # nft add chain filter input { type filter hook input \; } <cmdline>:1:24-49: Error: missing chain priority add chain filter input { type filter hook input ; } ^^^^^^^^^^^^^^^^^^^^^^^^^^ # nft add chain filter input { type filter hook input priority 0 hook input \; } <cmdline>:1:65-69: Error: you cannot set chain hook twice add chain filter input { type filter hook input priority 0 hook input ; } ^^^^^^^^^^ Signed-off-by: Pablo Neira Ayuso <pablo@xxxxxxxxxxxxx> --- include/rule.h | 11 +++++++++++ src/evaluate.c | 11 ++++++++++- src/parser_bison.y | 54 ++++++++++++++++++++++++++++++++++++---------------- 3 files changed, 59 insertions(+), 17 deletions(-) diff --git a/include/rule.h b/include/rule.h index 90836bc..b0ea1ba 100644 --- a/include/rule.h +++ b/include/rule.h @@ -92,6 +92,15 @@ extern void table_free(struct table *table); extern void table_add_hash(struct table *table); extern struct table *table_lookup(const struct handle *h); +enum chain_obj_flags { + CHAIN_OBJ_F_HOOK = (1 << 0), + CHAIN_OBJ_F_TYPE = (1 << 1), + CHAIN_OBJ_F_PRIO = (1 << 2), + CHAIN_OBJ_F_BASE = (CHAIN_OBJ_F_HOOK | + CHAIN_OBJ_F_TYPE | + CHAIN_OBJ_F_PRIO), +}; + /** * enum chain_flags - chain flags * @@ -112,6 +121,7 @@ enum chain_flags { * @hooknum: hook number (base chains) * @priority: hook priority (base chains) * @type: chain type + * @obj_flags: internal object flags (indicates structure field is set) * @rules: rules contained in the chain */ struct chain { @@ -123,6 +133,7 @@ struct chain { unsigned int hooknum; int priority; const char *type; + uint32_t obj_flags; struct scope scope; struct list_head rules; }; diff --git a/src/evaluate.c b/src/evaluate.c index a3484c6..79c49ae 100644 --- a/src/evaluate.c +++ b/src/evaluate.c @@ -1804,7 +1804,16 @@ static int chain_evaluate(struct eval_ctx *ctx, struct chain *chain) { struct rule *rule; - if (chain->flags & CHAIN_F_BASECHAIN) { + if (chain->flags & CHAIN_OBJ_F_BASE) { + if (!(chain->obj_flags & CHAIN_OBJ_F_HOOK)) + return chain_error(ctx, chain, "missing chain hook"); + if (!(chain->obj_flags & CHAIN_OBJ_F_PRIO)) + return chain_error(ctx, chain, "missing chain priority"); + if (!(chain->obj_flags & CHAIN_OBJ_F_TYPE)) + return chain_error(ctx, chain, "missing chain type"); + } + + if (chain->obj_flags & CHAIN_OBJ_F_HOOK) { chain->hooknum = str2hooknum(chain->handle.family, chain->hookstr); if (chain->hooknum == NF_INET_NUMHOOKS) diff --git a/src/parser_bison.y b/src/parser_bison.y index 6fc834d..6fa201d 100644 --- a/src/parser_bison.y +++ b/src/parser_bison.y @@ -1034,39 +1034,61 @@ type_identifier : identifier } ; -hook_spec : TYPE STRING HOOK STRING PRIORITY NUM +hook_spec : hook_options + ; + +hook_options : hook_options hook_option + | hook_option { - $<chain>0->type = chain_type_name_lookup($2); - if ($<chain>0->type == NULL) { - erec_queue(error(&@2, "unknown chain type %s", $2), + $<stmt>$ = $<stmt>0; + } + ; + +hook_option : TYPE STRING + { + if ($<chain>0->flags & CHAIN_OBJ_F_TYPE) { + erec_queue(error(&@$, "you cannot set chain type twice"), state->msgs); YYERROR; } - $<chain>0->hookstr = chain_hookname_lookup($4); - if ($<chain>0->hookstr == NULL) { - erec_queue(error(&@4, "unknown chain hook %s", $4), + $<chain>0->type = chain_type_name_lookup($2); + if ($<chain>0->type == NULL) { + erec_queue(error(&@2, "unknown chain type %s", $2), state->msgs); YYERROR; } - $<chain>0->priority = $6; - $<chain>0->flags |= CHAIN_F_BASECHAIN; + $<chain>0->obj_flags |= CHAIN_OBJ_F_TYPE; } - | TYPE STRING HOOK STRING PRIORITY DASH NUM + | HOOK STRING { - $<chain>0->type = chain_type_name_lookup($2); - if ($<chain>0->type == NULL) { - erec_queue(error(&@2, "unknown type name %s", $2), + if ($<chain>0->flags & CHAIN_OBJ_F_HOOK) { + erec_queue(error(&@$, "you cannot set chain hook twice"), state->msgs); YYERROR; } - $<chain>0->hookstr = chain_hookname_lookup($4); + $<chain>0->hookstr = chain_hookname_lookup($2); if ($<chain>0->hookstr == NULL) { - erec_queue(error(&@4, "unknown hook name %s", $4), + erec_queue(error(&@2, "unknown hook name %s", $2), state->msgs); YYERROR; } - $<chain>0->priority = -$7; $<chain>0->flags |= CHAIN_F_BASECHAIN; + $<chain>0->obj_flags |= CHAIN_OBJ_F_HOOK; + } + | PRIORITY NUM + { + if ($<chain>0->flags & CHAIN_OBJ_F_PRIO) { + erec_queue(error(&@$, "you cannot set chain priority twice"), + state->msgs); + YYERROR; + } + $<chain>0->priority = $2; + $<chain>0->obj_flags |= CHAIN_OBJ_F_PRIO; + } + | PRIORITY DASH NUM + { + $<chain>0->priority = -$3; + $<chain>0->obj_flags |= CHAIN_OBJ_F_PRIO; } ; -- 1.7.10.4 -- To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html