From dba4a9b4b5fe2c4b6929be799fdb9332fc653e1b Mon Sep 17 00:00:00 2001 From: Fernando Fernandez Mancera Date: Fri, 2 Aug 2019 12:12:10 +0200 Subject: src: allow variable in chain policy This patch allows you to use variables in chain policy definition, e.g. define default_policy = "accept" add table ip foo add chain ip foo bar {type filter hook input priority filter; policy $default_policy} Signed-off-by: Fernando Fernandez Mancera Signed-off-by: Pablo Neira Ayuso --- src/datatype.c | 30 ++++++++++++++++++++++++++++++ src/evaluate.c | 24 ++++++++++++++++++++++++ src/json.c | 5 ++++- src/mnl.c | 9 ++++++--- src/netlink.c | 8 +++++++- src/parser_bison.y | 23 +++++++++++++++++++---- src/parser_json.c | 17 ++++++++++++----- src/rule.c | 13 ++++++++++--- 8 files changed, 112 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/datatype.c b/src/datatype.c index 93eb1855..28f726f4 100644 --- a/src/datatype.c +++ b/src/datatype.c @@ -1292,3 +1292,33 @@ const struct datatype priority_type = { .desc = "priority type", .parse = priority_type_parse, }; + +static struct error_record *policy_type_parse(struct parse_ctx *ctx, + const struct expr *sym, + struct expr **res) +{ + int policy; + + if (!strcmp(sym->identifier, "accept")) + policy = NF_ACCEPT; + else if (!strcmp(sym->identifier, "drop")) + policy = NF_DROP; + else + return error(&sym->location, "wrong policy"); + + *res = constant_expr_alloc(&sym->location, &integer_type, + BYTEORDER_HOST_ENDIAN, + sizeof(int) * BITS_PER_BYTE, &policy); + return NULL; +} + +/* This datatype is not registered via datatype_register() + * since this datatype should not ever be used from either + * rules or elements. + */ +const struct datatype policy_type = { + .type = TYPE_STRING, + .name = "policy", + .desc = "policy type", + .parse = policy_type_parse, +}; diff --git a/src/evaluate.c b/src/evaluate.c index 1879eb0f..831eb7c2 100755 --- a/src/evaluate.c +++ b/src/evaluate.c @@ -3476,6 +3476,25 @@ static uint32_t str2hooknum(uint32_t family, const char *hook) return NF_INET_NUMHOOKS; } +static bool evaluate_policy(struct eval_ctx *ctx, struct expr **exprp) +{ + struct expr *expr; + + ctx->ectx.dtype = &policy_type; + ctx->ectx.len = NFT_NAME_MAXLEN * BITS_PER_BYTE; + if (expr_evaluate(ctx, exprp) < 0) + return false; + + expr = *exprp; + if (expr->etype != EXPR_VALUE) { + expr_error(ctx->msgs, expr, "%s is not a valid " + "policy expression", expr_name(expr)); + return false; + } + + return true; +} + static int chain_evaluate(struct eval_ctx *ctx, struct chain *chain) { struct table *table; @@ -3509,6 +3528,11 @@ static int chain_evaluate(struct eval_ctx *ctx, struct chain *chain) return __stmt_binary_error(ctx, &chain->priority.loc, NULL, "invalid priority expression %s in this context.", expr_name(chain->priority.expr)); + if (chain->policy) { + if (!evaluate_policy(ctx, &chain->policy)) + return chain_error(ctx, chain, "invalid policy expression %s", + expr_name(chain->policy)); + } } list_for_each_entry(rule, &chain->rules, list) { diff --git a/src/json.c b/src/json.c index fd184183..55ce0531 100644 --- a/src/json.c +++ b/src/json.c @@ -224,6 +224,7 @@ static json_t *chain_print_json(const struct chain *chain) { json_t *root, *tmp; int priority; + int policy; root = json_pack("{s:s, s:s, s:s, s:I}", "family", family2str(chain->handle.family), @@ -234,12 +235,14 @@ static json_t *chain_print_json(const struct chain *chain) if (chain->flags & CHAIN_F_BASECHAIN) { mpz_export_data(&priority, chain->priority.expr->value, BYTEORDER_HOST_ENDIAN, sizeof(int)); + mpz_export_data(&policy, chain->policy->value, + BYTEORDER_HOST_ENDIAN, sizeof(int)); tmp = json_pack("{s:s, s:s, s:i, s:s}", "type", chain->type, "hook", hooknum2str(chain->handle.family, chain->hooknum), "prio", priority, - "policy", chain_policy2str(chain->policy)); + "policy", chain_policy2str(policy)); if (chain->dev) json_object_set_new(tmp, "dev", json_string(chain->dev)); json_object_update(root, tmp); diff --git a/src/mnl.c b/src/mnl.c index 8921ccfb..f24d2ce0 100644 --- a/src/mnl.c +++ b/src/mnl.c @@ -519,6 +519,7 @@ int mnl_nft_chain_add(struct netlink_ctx *ctx, const struct cmd *cmd, struct nftnl_chain *nlc; struct nlmsghdr *nlh; int priority; + int policy; nlc = nftnl_chain_alloc(); if (nlc == NULL) @@ -539,9 +540,11 @@ int mnl_nft_chain_add(struct netlink_ctx *ctx, const struct cmd *cmd, nftnl_chain_set_str(nlc, NFTNL_CHAIN_TYPE, cmd->chain->type); } - if (cmd->chain->policy != -1) - nftnl_chain_set_u32(nlc, NFTNL_CHAIN_POLICY, - cmd->chain->policy); + if (cmd->chain->policy) { + mpz_export_data(&policy, cmd->chain->policy->value, + BYTEORDER_HOST_ENDIAN, sizeof(int)); + nftnl_chain_set_u32(nlc, NFTNL_CHAIN_POLICY, policy); + } if (cmd->chain->dev != NULL) nftnl_chain_set_str(nlc, NFTNL_CHAIN_DEV, cmd->chain->dev); diff --git a/src/netlink.c b/src/netlink.c index 93067ef5..aeeb12ea 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -370,6 +370,7 @@ struct chain *netlink_delinearize_chain(struct netlink_ctx *ctx, { struct chain *chain; int priority; + int policy; chain = chain_alloc(nftnl_chain_get_str(nlc, NFTNL_CHAIN_NAME)); chain->handle.family = @@ -396,7 +397,12 @@ struct chain *netlink_delinearize_chain(struct netlink_ctx *ctx, &priority); chain->type = xstrdup(nftnl_chain_get_str(nlc, NFTNL_CHAIN_TYPE)); - chain->policy = + policy = nftnl_chain_get_u32(nlc, NFTNL_CHAIN_POLICY); + chain->policy = constant_expr_alloc(&netlink_location, + &integer_type, + BYTEORDER_HOST_ENDIAN, + sizeof(int) * BITS_PER_BYTE, + &policy); nftnl_chain_get_u32(nlc, NFTNL_CHAIN_POLICY); if (nftnl_chain_is_set(nlc, NFTNL_CHAIN_DEV)) { chain->dev = diff --git a/src/parser_bison.y b/src/parser_bison.y index f2b1e5ac..939b9a8d 100644 --- a/src/parser_bison.y +++ b/src/parser_bison.y @@ -636,8 +636,8 @@ int nft_lex(void *, void *, void *); %type meter_stmt meter_stmt_alloc flow_stmt_legacy_alloc %destructor { stmt_free($$); } meter_stmt meter_stmt_alloc flow_stmt_legacy_alloc -%type symbol_expr verdict_expr integer_expr variable_expr chain_expr -%destructor { expr_free($$); } symbol_expr verdict_expr integer_expr variable_expr chain_expr +%type symbol_expr verdict_expr integer_expr variable_expr chain_expr policy_expr +%destructor { expr_free($$); } symbol_expr verdict_expr integer_expr variable_expr chain_expr policy_expr %type primary_expr shift_expr and_expr %destructor { expr_free($$); } primary_expr shift_expr and_expr %type exclusive_or_expr inclusive_or_expr @@ -2033,17 +2033,32 @@ dev_spec : DEVICE string { $$ = $2; } | /* empty */ { $$ = NULL; } ; -policy_spec : POLICY chain_policy +policy_spec : POLICY policy_expr { - if ($0->policy != -1) { + if ($0->policy) { erec_queue(error(&@$, "you cannot set chain policy twice"), state->msgs); + expr_free($2); YYERROR; } $0->policy = $2; } ; +policy_expr : variable_expr + { + datatype_set($1->sym->expr, &policy_type); + $$ = $1; + } + | chain_policy + { + $$ = constant_expr_alloc(&@$, &integer_type, + BYTEORDER_HOST_ENDIAN, + sizeof(int) * + BITS_PER_BYTE, &$1); + } + ; + chain_policy : ACCEPT { $$ = NF_ACCEPT; } | DROP { $$ = NF_DROP; } ; diff --git a/src/parser_json.c b/src/parser_json.c index a45234ad..956233b9 100644 --- a/src/parser_json.c +++ b/src/parser_json.c @@ -2530,13 +2530,20 @@ static struct cmd *json_parse_cmd_add_table(struct json_ctx *ctx, json_t *root, return cmd_alloc(op, obj, &h, int_loc, NULL); } -static int parse_policy(const char *policy) +static struct expr *parse_policy(const char *policy) { + int policy_num; + if (!strcmp(policy, "accept")) - return NF_ACCEPT; - if (!strcmp(policy, "drop")) - return NF_DROP; - return -1; + policy_num = NF_ACCEPT; + else if (!strcmp(policy, "drop")) + policy_num = NF_DROP; + else + return NULL; + + return constant_expr_alloc(int_loc, &integer_type, + BYTEORDER_HOST_ENDIAN, + sizeof(int) * BITS_PER_BYTE, &policy_num); } static struct cmd *json_parse_cmd_add_chain(struct json_ctx *ctx, json_t *root, diff --git a/src/rule.c b/src/rule.c index 2aca8aff..5655e8c0 100644 --- a/src/rule.c +++ b/src/rule.c @@ -798,7 +798,7 @@ struct chain *chain_alloc(const char *name) if (name != NULL) chain->handle.chain.name = xstrdup(name); - chain->policy = -1; + chain->policy = NULL; return chain; } @@ -822,6 +822,7 @@ void chain_free(struct chain *chain) if (chain->dev != NULL) xfree(chain->dev); expr_free(chain->priority.expr); + expr_free(chain->policy); xfree(chain); } @@ -1098,12 +1099,15 @@ static void chain_print_declaration(const struct chain *chain, struct output_ctx *octx) { char priobuf[STD_PRIO_BUFSIZE]; + int policy; nft_print(octx, "\tchain %s {", chain->handle.chain.name); if (nft_output_handle(octx)) nft_print(octx, " # handle %" PRIu64, chain->handle.handle.id); nft_print(octx, "\n"); if (chain->flags & CHAIN_F_BASECHAIN) { + mpz_export_data(&policy, chain->policy->value, + BYTEORDER_HOST_ENDIAN, sizeof(int)); nft_print(octx, "\t\ttype %s hook %s", chain->type, hooknum2str(chain->handle.family, chain->hooknum)); if (chain->dev != NULL) @@ -1112,7 +1116,7 @@ static void chain_print_declaration(const struct chain *chain, prio2str(octx, priobuf, sizeof(priobuf), chain->handle.family, chain->hooknum, chain->priority.expr), - chain_policy2str(chain->policy)); + chain_policy2str(policy)); } } @@ -1133,17 +1137,20 @@ static void chain_print(const struct chain *chain, struct output_ctx *octx) void chain_print_plain(const struct chain *chain, struct output_ctx *octx) { char priobuf[STD_PRIO_BUFSIZE]; + int policy; nft_print(octx, "chain %s %s %s", family2str(chain->handle.family), chain->handle.table.name, chain->handle.chain.name); if (chain->flags & CHAIN_F_BASECHAIN) { + mpz_export_data(&policy, chain->policy->value, + BYTEORDER_HOST_ENDIAN, sizeof(int)); nft_print(octx, " { type %s hook %s priority %s; policy %s; }", chain->type, chain->hookstr, prio2str(octx, priobuf, sizeof(priobuf), chain->handle.family, chain->hooknum, chain->priority.expr), - chain_policy2str(chain->policy)); + chain_policy2str(policy)); } if (nft_output_handle(octx)) nft_print(octx, " # handle %" PRIu64, chain->handle.handle.id); -- cgit v1.2.3