summaryrefslogtreecommitdiffstats
path: root/src/rule.c
diff options
context:
space:
mode:
authorPhil Sutter <phil@nwl.cc>2018-03-16 00:03:19 +0100
committerPablo Neira Ayuso <pablo@netfilter.org>2018-03-16 09:58:39 +0100
commit6979625686ec8d915f5ad5fdc28f24f55b6be3f7 (patch)
treee358bb0c0335622f99c374386ba2f1d8d2dbf20d /src/rule.c
parent70b31b1ce73e704d4387b1262e8b97785ffe64f7 (diff)
relational: Eliminate meta OPs
With a bit of code reorganization, relational meta OPs OP_RANGE, OP_FLAGCMP and OP_LOOKUP become unused and can be removed. The only meta OP left is OP_IMPLICIT which is usually treated as alias to OP_EQ. Though it needs to stay in place for one reason: When matching against a bitmask (e.g. TCP flags or conntrack states), it has a different meaning: | nft --debug=netlink add rule ip t c tcp flags syn | ip t c | [ meta load l4proto => reg 1 ] | [ cmp eq reg 1 0x00000006 ] | [ payload load 1b @ transport header + 13 => reg 1 ] | [ bitwise reg 1 = (reg=1 & 0x00000002 ) ^ 0x00000000 ] | [ cmp neq reg 1 0x00000000 ] | nft --debug=netlink add rule ip t c tcp flags == syn | ip t c | [ meta load l4proto => reg 1 ] | [ cmp eq reg 1 0x00000006 ] | [ payload load 1b @ transport header + 13 => reg 1 ] | [ cmp eq reg 1 0x00000002 ] OP_IMPLICIT creates a match which just checks the given flag is present, while OP_EQ creates a match which ensures the given flag and no other is present. Signed-off-by: Phil Sutter <phil@nwl.cc> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'src/rule.c')
-rw-r--r--src/rule.c13
1 files changed, 12 insertions, 1 deletions
diff --git a/src/rule.c b/src/rule.c
index c5bf6593..4334efac 100644
--- a/src/rule.c
+++ b/src/rule.c
@@ -2130,6 +2130,16 @@ static int payload_match_stmt_cmp(const void *p1, const void *p2)
return e1->left->payload.offset - e2->left->payload.offset;
}
+static bool relational_ops_match(const struct expr *e1, const struct expr *e2)
+{
+ enum ops op1, op2;
+
+ op1 = e1->op == OP_IMPLICIT ? OP_EQ : e1->op;
+ op2 = e2->op == OP_IMPLICIT ? OP_EQ : e2->op;
+
+ return op1 == op2;
+}
+
static void payload_do_merge(struct stmt *sa[], unsigned int n)
{
struct expr *last, *this, *expr1, *expr2;
@@ -2144,7 +2154,7 @@ static void payload_do_merge(struct stmt *sa[], unsigned int n)
this = stmt->expr;
if (!payload_can_merge(last->left, this->left) ||
- last->op != this->op) {
+ !relational_ops_match(last, this)) {
last = this;
j = i;
continue;
@@ -2227,6 +2237,7 @@ static void payload_try_merge(const struct rule *rule)
continue;
switch (stmt->expr->op) {
case OP_EQ:
+ case OP_IMPLICIT:
case OP_NEQ:
break;
default: