summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPablo Neira Ayuso <pablo@netfilter.org>2021-05-13 01:34:01 +0200
committerPablo Neira Ayuso <pablo@netfilter.org>2021-05-16 01:01:32 +0200
commitc3d57114f119b89ec0caa0b4dfa8527826a38792 (patch)
treee05672750206c02c70d0927cbd4b8ca6aae4b31c /src
parent3adb0316e2b5683acd0f93661a278f059a13cc5b (diff)
parser_bison: add shortcut syntax for matching flags without binary operations
This patch adds the following shortcut syntax: expression flags / flags instead of: expression and flags == flags For example: tcp flags syn,ack / syn,ack,fin,rst ^^^^^^^ ^^^^^^^^^^^^^^^ value mask instead of: tcp flags and (syn|ack|fin|rst) == syn|ack The second list of comma-separated flags represents the mask which are examined and the first list of comma-separated flags must be set. You can also use the != operator with this syntax: tcp flags != fin,rst / syn,ack,fin,rst This shortcut is based on the prefix notation, but it is also similar to the iptables tcp matching syntax. This patch introduces the flagcmp expression to print the tcp flags in this new notation. The delinearize path transforms the binary expression to this new flagcmp expression whenever possible. Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'src')
-rw-r--r--src/evaluate.c17
-rw-r--r--src/expression.c51
-rw-r--r--src/json.c14
-rw-r--r--src/netlink_delinearize.c64
-rw-r--r--src/parser_bison.y16
5 files changed, 140 insertions, 22 deletions
diff --git a/src/evaluate.c b/src/evaluate.c
index 2e31ed10..a3a1d1c0 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -2134,6 +2134,21 @@ static int expr_evaluate_xfrm(struct eval_ctx *ctx, struct expr **exprp)
return expr_evaluate_primary(ctx, exprp);
}
+static int expr_evaluate_flagcmp(struct eval_ctx *ctx, struct expr **exprp)
+{
+ struct expr *expr = *exprp, *binop, *rel;
+
+ binop = binop_expr_alloc(&expr->location, OP_AND,
+ expr_get(expr->flagcmp.expr),
+ expr_get(expr->flagcmp.mask));
+ rel = relational_expr_alloc(&expr->location, expr->op, binop,
+ expr_get(expr->flagcmp.value));
+ expr_free(expr);
+ *exprp = rel;
+
+ return expr_evaluate(ctx, exprp);
+}
+
static int expr_evaluate(struct eval_ctx *ctx, struct expr **expr)
{
if (ctx->nft->debug_mask & NFT_DEBUG_EVALUATION) {
@@ -2203,6 +2218,8 @@ static int expr_evaluate(struct eval_ctx *ctx, struct expr **expr)
return expr_evaluate_xfrm(ctx, expr);
case EXPR_SET_ELEM_CATCHALL:
return 0;
+ case EXPR_FLAGCMP:
+ return expr_evaluate_flagcmp(ctx, expr);
default:
BUG("unknown expression type %s\n", expr_name(*expr));
}
diff --git a/src/expression.c b/src/expression.c
index b3400751..7ae075d2 100644
--- a/src/expression.c
+++ b/src/expression.c
@@ -1351,6 +1351,56 @@ struct expr *set_elem_catchall_expr_alloc(const struct location *loc)
return expr;
}
+static void flagcmp_expr_print(const struct expr *expr, struct output_ctx *octx)
+{
+ expr_print(expr->flagcmp.expr, octx);
+ nft_print(octx, " ");
+ expr_print(expr->flagcmp.value, octx);
+ nft_print(octx, " / ");
+ expr_print(expr->flagcmp.mask, octx);
+}
+
+static void flagcmp_expr_clone(struct expr *new, const struct expr *expr)
+{
+ new->flagcmp.expr = expr_clone(expr->flagcmp.expr);
+ new->flagcmp.mask = expr_clone(expr->flagcmp.mask);
+ new->flagcmp.value = expr_clone(expr->flagcmp.value);
+}
+
+static void flagcmp_expr_destroy(struct expr *expr)
+{
+ expr_free(expr->flagcmp.expr);
+ expr_free(expr->flagcmp.mask);
+ expr_free(expr->flagcmp.value);
+}
+
+static const struct expr_ops flagcmp_expr_ops = {
+ .type = EXPR_FLAGCMP,
+ .name = "flags comparison",
+ .print = flagcmp_expr_print,
+ .json = flagcmp_expr_json,
+ .clone = flagcmp_expr_clone,
+ .destroy = flagcmp_expr_destroy,
+};
+
+struct expr *flagcmp_expr_alloc(const struct location *loc, enum ops op,
+ struct expr *match, struct expr *mask,
+ struct expr *value)
+{
+ struct expr *expr;
+
+ expr = expr_alloc(loc, EXPR_FLAGCMP, match->dtype, match->byteorder,
+ match->len);
+ expr->op = op;
+ expr->flagcmp.expr = match;
+ expr->flagcmp.mask = mask;
+ /* json output needs this operation for compatibility */
+ expr->flagcmp.mask->op = OP_OR;
+ expr->flagcmp.value = value;
+
+ return expr;
+}
+
void range_expr_value_low(mpz_t rop, const struct expr *expr)
{
switch (expr->etype) {
@@ -1427,6 +1477,7 @@ static const struct expr_ops *__expr_ops_by_type(enum expr_types etype)
case EXPR_FIB: return &fib_expr_ops;
case EXPR_XFRM: return &xfrm_expr_ops;
case EXPR_SET_ELEM_CATCHALL: return &set_elem_catchall_expr_ops;
+ case EXPR_FLAGCMP: return &flagcmp_expr_ops;
}
BUG("Unknown expression type %d\n", etype);
diff --git a/src/json.c b/src/json.c
index b4197b2f..69ca9697 100644
--- a/src/json.c
+++ b/src/json.c
@@ -479,6 +479,20 @@ static json_t *table_print_json(const struct table *table)
return json_pack("{s:o}", "table", root);
}
+json_t *flagcmp_expr_json(const struct expr *expr, struct output_ctx *octx)
+{
+ json_t *left;
+
+ left = json_pack("{s:[o, o]}", expr_op_symbols[OP_AND],
+ expr_print_json(expr->flagcmp.expr, octx),
+ expr_print_json(expr->flagcmp.mask, octx));
+
+ return json_pack("{s:{s:s, s:o, s:o}}", "match",
+ "op", expr_op_symbols[expr->op] ? : "in",
+ "left", left,
+ "right", expr_print_json(expr->flagcmp.value, octx));
+}
+
json_t *binop_expr_json(const struct expr *expr, struct output_ctx *octx)
{
return json_pack("{s:[o, o]}", expr_op_symbols[expr->op],
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
index 81fe4c16..75869d33 100644
--- a/src/netlink_delinearize.c
+++ b/src/netlink_delinearize.c
@@ -2166,35 +2166,55 @@ static void map_binop_postprocess(struct rule_pp_ctx *ctx, struct expr *expr)
binop_postprocess(ctx, expr);
}
-static void relational_binop_postprocess(struct rule_pp_ctx *ctx, struct expr *expr)
+static void relational_binop_postprocess(struct rule_pp_ctx *ctx,
+ struct expr **exprp)
{
- struct expr *binop = expr->left, *value = expr->right;
+ struct expr *expr = *exprp, *binop = expr->left, *value = expr->right;
if (binop->op == OP_AND && (expr->op == OP_NEQ || expr->op == OP_EQ) &&
value->dtype->basetype &&
- value->dtype->basetype->type == TYPE_BITMASK &&
- value->etype == EXPR_VALUE &&
- !mpz_cmp_ui(value->value, 0)) {
- /* Flag comparison: data & flags != 0
- *
- * Split the flags into a list of flag values and convert the
- * op to OP_EQ.
- */
- expr_free(value);
-
- expr->left = expr_get(binop->left);
- expr->right = binop_tree_to_list(NULL, binop->right);
- switch (expr->op) {
- case OP_NEQ:
- expr->op = OP_IMPLICIT;
+ value->dtype->basetype->type == TYPE_BITMASK) {
+ switch (value->etype) {
+ case EXPR_VALUE:
+ if (!mpz_cmp_ui(value->value, 0)) {
+ /* Flag comparison: data & flags != 0
+ *
+ * Split the flags into a list of flag values and convert the
+ * op to OP_EQ.
+ */
+ expr_free(value);
+
+ expr->left = expr_get(binop->left);
+ expr->right = binop_tree_to_list(NULL, binop->right);
+ switch (expr->op) {
+ case OP_NEQ:
+ expr->op = OP_IMPLICIT;
+ break;
+ case OP_EQ:
+ expr->op = OP_NEG;
+ break;
+ default:
+ BUG("unknown operation type %d\n", expr->op);
+ }
+ expr_free(binop);
+ } else {
+ *exprp = flagcmp_expr_alloc(&expr->location, expr->op,
+ expr_get(binop->left),
+ binop_tree_to_list(NULL, binop->right),
+ expr_get(value));
+ expr_free(expr);
+ }
break;
- case OP_EQ:
- expr->op = OP_NEG;
+ case EXPR_BINOP:
+ *exprp = flagcmp_expr_alloc(&expr->location, expr->op,
+ expr_get(binop->left),
+ binop_tree_to_list(NULL, binop->right),
+ binop_tree_to_list(NULL, value));
+ expr_free(expr);
break;
default:
- BUG("unknown operation type %d\n", expr->op);
+ break;
}
- expr_free(binop);
} else if (binop->left->dtype->flags & DTYPE_F_PREFIX &&
binop->op == OP_AND && expr->right->etype == EXPR_VALUE &&
expr_mask_is_prefix(binop->right)) {
@@ -2403,7 +2423,7 @@ static void expr_postprocess(struct rule_pp_ctx *ctx, struct expr **exprp)
meta_match_postprocess(ctx, expr);
break;
case EXPR_BINOP:
- relational_binop_postprocess(ctx, expr);
+ relational_binop_postprocess(ctx, exprp);
break;
default:
break;
diff --git a/src/parser_bison.y b/src/parser_bison.y
index 000eb40a..cdb04fa8 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -4463,6 +4463,22 @@ relational_expr : expr /* implicit */ rhs_expr
{
$$ = relational_expr_alloc(&@$, OP_IMPLICIT, $1, $2);
}
+ | expr /* implicit */ basic_rhs_expr SLASH list_rhs_expr
+ {
+ $$ = flagcmp_expr_alloc(&@$, OP_EQ, $1, $4, $2);
+ }
+ | expr /* implicit */ list_rhs_expr SLASH list_rhs_expr
+ {
+ $$ = flagcmp_expr_alloc(&@$, OP_EQ, $1, $4, $2);
+ }
+ | expr relational_op basic_rhs_expr SLASH list_rhs_expr
+ {
+ $$ = flagcmp_expr_alloc(&@$, $2, $1, $5, $3);
+ }
+ | expr relational_op list_rhs_expr SLASH list_rhs_expr
+ {
+ $$ = flagcmp_expr_alloc(&@$, $2, $1, $5, $3);
+ }
| expr relational_op rhs_expr
{
$$ = relational_expr_alloc(&@2, $2, $1, $3);