From f1e8a129ee428419a0d5a45a2f410e8e4008d109 Mon Sep 17 00:00:00 2001 From: Fernando Fernandez Mancera Date: Fri, 24 May 2019 15:06:47 +0200 Subject: src: Introduce chain_expr in jump and goto statements Introduce expressions as a chain in jump and goto statements. This is going to be used to support variables as a chain in the following patches. Signed-off-by: Fernando Fernandez Mancera Signed-off-by: Pablo Neira Ayuso --- src/datatype.c | 22 ++++++++++++++++++++-- src/evaluate.c | 4 ++++ src/expression.c | 12 ++++++------ src/json.c | 6 +++--- src/netlink.c | 26 +++++++++++++++++++++----- src/parser_bison.y | 17 +++++++++++++---- src/parser_json.c | 9 +++++++-- 7 files changed, 74 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/src/datatype.c b/src/datatype.c index ac9f2af1..10f185bc 100644 --- a/src/datatype.c +++ b/src/datatype.c @@ -254,6 +254,8 @@ const struct datatype invalid_type = { static void verdict_type_print(const struct expr *expr, struct output_ctx *octx) { + char chain[NFT_CHAIN_MAXNAMELEN]; + switch (expr->verdict) { case NFT_CONTINUE: nft_print(octx, "continue"); @@ -262,10 +264,26 @@ static void verdict_type_print(const struct expr *expr, struct output_ctx *octx) nft_print(octx, "break"); break; case NFT_JUMP: - nft_print(octx, "jump %s", expr->chain); + if (expr->chain->etype == EXPR_VALUE) { + mpz_export_data(chain, expr->chain->value, + BYTEORDER_HOST_ENDIAN, + NFT_CHAIN_MAXNAMELEN); + nft_print(octx, "jump %s", chain); + } else { + nft_print(octx, "jump "); + expr_print(expr->chain, octx); + } break; case NFT_GOTO: - nft_print(octx, "goto %s", expr->chain); + if (expr->chain->etype == EXPR_VALUE) { + mpz_export_data(chain, expr->chain->value, + BYTEORDER_HOST_ENDIAN, + NFT_CHAIN_MAXNAMELEN); + nft_print(octx, "goto %s", chain); + } else { + nft_print(octx, "goto "); + expr_print(expr->chain, octx); + } break; case NFT_RETURN: nft_print(octx, "return"); diff --git a/src/evaluate.c b/src/evaluate.c index 21d9e146..83940378 100644 --- a/src/evaluate.c +++ b/src/evaluate.c @@ -1947,6 +1947,10 @@ static int stmt_evaluate_verdict(struct eval_ctx *ctx, struct stmt *stmt) case EXPR_VERDICT: if (stmt->expr->verdict != NFT_CONTINUE) stmt->flags |= STMT_F_TERMINAL; + if (stmt->expr->chain != NULL) { + if (expr_evaluate(ctx, &stmt->expr->chain) < 0) + return -1; + } break; case EXPR_MAP: break; diff --git a/src/expression.c b/src/expression.c index eece12e4..a41e2daf 100644 --- a/src/expression.c +++ b/src/expression.c @@ -207,22 +207,22 @@ static bool verdict_expr_cmp(const struct expr *e1, const struct expr *e2) if ((e1->verdict == NFT_JUMP || e1->verdict == NFT_GOTO) && - strcmp(e1->chain, e2->chain)) - return false; + expr_cmp(e1->chain, e2->chain)) + return true; - return true; + return false; } static void verdict_expr_clone(struct expr *new, const struct expr *expr) { new->verdict = expr->verdict; if (expr->chain != NULL) - new->chain = xstrdup(expr->chain); + mpz_init_set(new->chain->value, expr->chain->value); } static void verdict_expr_destroy(struct expr *expr) { - xfree(expr->chain); + expr_free(expr->chain); } static const struct expr_ops verdict_expr_ops = { @@ -236,7 +236,7 @@ static const struct expr_ops verdict_expr_ops = { }; struct expr *verdict_expr_alloc(const struct location *loc, - int verdict, const char *chain) + int verdict, struct expr *chain) { struct expr *expr; diff --git a/src/json.c b/src/json.c index ff79b0cc..a503a975 100644 --- a/src/json.c +++ b/src/json.c @@ -673,14 +673,14 @@ json_t *verdict_expr_json(const struct expr *expr, struct output_ctx *octx) { NF_QUEUE, "queue", false }, }; const char *name = NULL; - const char *chain = NULL; + json_t *chain = NULL; unsigned int i; for (i = 0; i < array_size(verdict_tbl); i++) { if (expr->verdict == verdict_tbl[i].verdict) { name = verdict_tbl[i].name; if (verdict_tbl[i].chain && expr->chain) - chain = expr->chain; + chain = expr_print_json(expr->chain, octx); break; } } @@ -689,7 +689,7 @@ json_t *verdict_expr_json(const struct expr *expr, struct output_ctx *octx) return NULL; } if (chain) - return json_pack("{s:{s:s}}", name, "target", chain); + return json_pack("{s:{s:o}}", name, "target", chain); else return json_pack("{s:n}", name); } diff --git a/src/netlink.c b/src/netlink.c index c051ae6c..ef12cb01 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -218,12 +218,17 @@ static void netlink_gen_constant_data(const struct expr *expr, static void netlink_gen_verdict(const struct expr *expr, struct nft_data_linearize *data) { + char chain[NFT_CHAIN_MAXNAMELEN]; + data->verdict = expr->verdict; switch (expr->verdict) { case NFT_JUMP: case NFT_GOTO: - snprintf(data->chain, NFT_CHAIN_MAXNAMELEN, "%s", expr->chain); + mpz_export_data(chain, expr->chain->value, + BYTEORDER_HOST_ENDIAN, + NFT_CHAIN_MAXNAMELEN); + snprintf(data->chain, NFT_CHAIN_MAXNAMELEN, "%s", chain); data->chain[NFT_CHAIN_MAXNAMELEN-1] = '\0'; break; } @@ -253,12 +258,15 @@ struct expr *netlink_alloc_value(const struct location *loc, static struct expr *netlink_alloc_verdict(const struct location *loc, const struct nft_data_delinearize *nld) { - char *chain; + struct expr *chain; switch (nld->verdict) { case NFT_JUMP: case NFT_GOTO: - chain = xstrdup(nld->chain); + chain = constant_expr_alloc(loc, &string_type, + BYTEORDER_HOST_ENDIAN, + NFT_CHAIN_MAXNAMELEN * + BITS_PER_BYTE, nld->chain); break; default: chain = NULL; @@ -1153,14 +1161,22 @@ static void trace_print_expr(const struct nftnl_trace *nlt, unsigned int attr, static void trace_print_verdict(const struct nftnl_trace *nlt, struct output_ctx *octx) { + struct expr *chain_expr = NULL; const char *chain = NULL; unsigned int verdict; struct expr *expr; verdict = nftnl_trace_get_u32(nlt, NFTNL_TRACE_VERDICT); - if (nftnl_trace_is_set(nlt, NFTNL_TRACE_JUMP_TARGET)) + if (nftnl_trace_is_set(nlt, NFTNL_TRACE_JUMP_TARGET)) { chain = xstrdup(nftnl_trace_get_str(nlt, NFTNL_TRACE_JUMP_TARGET)); - expr = verdict_expr_alloc(&netlink_location, verdict, chain); + chain_expr = constant_expr_alloc(&netlink_location, + &string_type, + BYTEORDER_HOST_ENDIAN, + NFT_CHAIN_MAXNAMELEN + * BITS_PER_BYTE, + chain); + } + expr = verdict_expr_alloc(&netlink_location, verdict, chain_expr); nft_print(octx, "verdict "); expr_print(expr, octx); diff --git a/src/parser_bison.y b/src/parser_bison.y index 8c8cd432..f2583ade 100644 --- a/src/parser_bison.y +++ b/src/parser_bison.y @@ -618,8 +618,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 -%destructor { expr_free($$); } symbol_expr verdict_expr integer_expr variable_expr +%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 primary_expr shift_expr and_expr %destructor { expr_free($$); } primary_expr shift_expr and_expr %type exclusive_or_expr inclusive_or_expr @@ -3827,11 +3827,11 @@ verdict_expr : ACCEPT { $$ = verdict_expr_alloc(&@$, NFT_CONTINUE, NULL); } - | JUMP identifier + | JUMP chain_expr { $$ = verdict_expr_alloc(&@$, NFT_JUMP, $2); } - | GOTO identifier + | GOTO chain_expr { $$ = verdict_expr_alloc(&@$, NFT_GOTO, $2); } @@ -3841,6 +3841,15 @@ verdict_expr : ACCEPT } ; +chain_expr : identifier + { + $$ = constant_expr_alloc(&@$, &string_type, + BYTEORDER_HOST_ENDIAN, + NFT_CHAIN_MAXNAMELEN * + BITS_PER_BYTE, $1); + } + ; + meta_expr : META meta_key { $$ = meta_expr_alloc(&@$, $2); diff --git a/src/parser_json.c b/src/parser_json.c index 1b3e0862..80f17d85 100644 --- a/src/parser_json.c +++ b/src/parser_json.c @@ -1068,10 +1068,16 @@ static struct expr *json_parse_verdict_expr(struct json_ctx *ctx, { NF_ACCEPT, "accept", false }, { NF_DROP, "drop", false }, }; + struct expr *chain_expr = NULL; const char *chain = NULL; unsigned int i; json_unpack(root, "{s:s}", "target", &chain); + if (!chain) + chain_expr = constant_expr_alloc(int_loc, &string_type, + BYTEORDER_HOST_ENDIAN, + NFT_CHAIN_MAXNAMELEN * + BITS_PER_BYTE, chain); for (i = 0; i < array_size(verdict_tbl); i++) { if (strcmp(type, verdict_tbl[i].name)) @@ -1082,8 +1088,7 @@ static struct expr *json_parse_verdict_expr(struct json_ctx *ctx, return NULL; return verdict_expr_alloc(int_loc, - verdict_tbl[i].verdict, - chain ? xstrdup(chain) : NULL); + verdict_tbl[i].verdict, chain_expr); } json_error(ctx, "Unknown verdict '%s'.", type); return NULL; -- cgit v1.2.3