c3d57114f119 ("parser_bison: add shortcut syntax for matching flags without binary operations") provides a similar syntax to iptables using a prefix representation for flag matching. Restore original representation using binop when listing the ruleset. The parser still accepts the prefix notation for backward compatibility. Signed-off-by: Pablo Neira Ayuso <pablo@xxxxxxxxxxxxx> --- src/netlink_delinearize.c | 65 ++++++------------- tests/py/inet/tcp.t | 16 ++--- .../testcases/nft-f/dumps/sample-ruleset.nft | 4 +- tests/shell/testcases/packetpath/tcp_options | 16 ++--- 4 files changed, 37 insertions(+), 64 deletions(-) diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c index 1d30a78c3441..405a065bc98f 100644 --- a/src/netlink_delinearize.c +++ b/src/netlink_delinearize.c @@ -2517,56 +2517,29 @@ static void relational_binop_postprocess(struct rule_pp_ctx *ctx, if (binop->op == OP_AND && (expr->op == OP_NEQ || expr->op == OP_EQ) && right->dtype->basetype && - right->dtype->basetype->type == TYPE_BITMASK) { - switch (right->etype) { - case EXPR_VALUE: - if (!mpz_cmp_ui(right->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(right); - - 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 if (binop->right->etype == EXPR_VALUE && - right->etype == EXPR_VALUE && - !mpz_cmp(right->value, binop->right->value)) { - /* Skip flag / flag representation for: - * data & flag == flag - * data & flag != flag - */ - ; - } else { - *exprp = flagcmp_expr_alloc(&expr->location, expr->op, - expr_get(binop->left), - binop_tree_to_list(NULL, binop->right), - expr_get(right)); - expr_free(expr); - } + right->dtype->basetype->type == TYPE_BITMASK && + right->etype == EXPR_VALUE && + !mpz_cmp_ui(right->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(right); + + 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 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, right)); - expr_free(expr); + case OP_EQ: + expr->op = OP_NEG; break; default: - break; + BUG("unknown operation type %d\n", expr->op); } + 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)) { diff --git a/tests/py/inet/tcp.t b/tests/py/inet/tcp.t index f51ebd36b503..913bf99e3480 100644 --- a/tests/py/inet/tcp.t +++ b/tests/py/inet/tcp.t @@ -68,8 +68,8 @@ tcp flags != { fin, urg, ecn, cwr} drop;ok tcp flags cwr;ok tcp flags != cwr;ok tcp flags == syn;ok -tcp flags fin,syn / fin,syn;ok -tcp flags != syn / fin,syn;ok +tcp flags fin,syn / fin,syn;ok;tcp flags (fin | syn) == (fin | syn) +tcp flags != syn / fin,syn;ok;tcp flags (fin | syn) == syn tcp flags & syn != 0;ok;tcp flags syn tcp flags & syn == 0;ok;tcp flags ! syn tcp flags & (syn | ack) != 0;ok;tcp flags syn,ack @@ -77,12 +77,12 @@ tcp flags & (syn | ack) == 0;ok;tcp flags ! syn,ack # it should be possible to transform this to: tcp flags syn tcp flags & syn == syn;ok tcp flags & syn != syn;ok -tcp flags & (fin | syn | rst | ack) syn;ok;tcp flags syn / fin,syn,rst,ack -tcp flags & (fin | syn | rst | ack) == syn;ok;tcp flags syn / fin,syn,rst,ack -tcp flags & (fin | syn | rst | ack) != syn;ok;tcp flags != syn / fin,syn,rst,ack -tcp flags & (fin | syn | rst | ack) == (syn | ack);ok;tcp flags syn,ack / fin,syn,rst,ack -tcp flags & (fin | syn | rst | ack) != (syn | ack);ok;tcp flags != syn,ack / fin,syn,rst,ack -tcp flags & (syn | ack) == (syn | ack);ok;tcp flags syn,ack / syn,ack +tcp flags & (fin | syn | rst | ack) syn;ok +tcp flags & (fin | syn | rst | ack) == syn;ok +tcp flags & (fin | syn | rst | ack) != syn;ok +tcp flags & (fin | syn | rst | ack) == (syn | ack);ok +tcp flags & (fin | syn | rst | ack) != (syn | ack);ok +tcp flags & (syn | ack) == (syn | ack);ok tcp flags & (fin | syn | rst | psh | ack | urg | ecn | cwr) == fin | syn | rst | psh | ack | urg | ecn | cwr;ok;tcp flags == 0xff tcp flags { syn, syn | ack };ok tcp flags & (fin | syn | rst | psh | ack | urg) == { fin, ack, psh | ack, fin | psh | ack };ok diff --git a/tests/shell/testcases/nft-f/dumps/sample-ruleset.nft b/tests/shell/testcases/nft-f/dumps/sample-ruleset.nft index 480b694a8989..1a9f4e7a4afa 100644 --- a/tests/shell/testcases/nft-f/dumps/sample-ruleset.nft +++ b/tests/shell/testcases/nft-f/dumps/sample-ruleset.nft @@ -73,7 +73,7 @@ table inet filter { chain ct_new_pre { jump rpfilter - tcp flags != syn / fin,syn,rst,ack counter packets 0 bytes 0 drop + tcp flags & (fin | syn | rst | ack) != syn counter packets 0 bytes 0 drop iifname "eth0" meta nfproto vmap { ipv4 : jump blacklist_input_ipv4, ipv6 : jump blacklist_input_ipv6 } } @@ -131,7 +131,7 @@ table inet filter { type filter hook forward priority mangle; policy accept; oifname "eth0" jump { ct state new meta nfproto vmap { ipv4 : jump blacklist_output_ipv4, ipv6 : jump blacklist_output_ipv6 } - tcp flags syn / syn,rst tcp option maxseg size set rt mtu + tcp flags & (syn | rst) == syn tcp option maxseg size set rt mtu } } diff --git a/tests/shell/testcases/packetpath/tcp_options b/tests/shell/testcases/packetpath/tcp_options index 1c9ee5329b26..88552226ee3a 100755 --- a/tests/shell/testcases/packetpath/tcp_options +++ b/tests/shell/testcases/packetpath/tcp_options @@ -15,14 +15,14 @@ table inet t { chain c { type filter hook output priority 0; tcp dport != 22345 accept - tcp flags syn / fin,syn,rst,ack tcp option 254 length ge 4 counter name nomatchc drop - tcp flags syn / fin,syn,rst,ack tcp option fastopen length ge 2 reset tcp option fastopen counter name nomatchc - tcp flags syn / fin,syn,rst,ack tcp option sack-perm missing counter name nomatchc - tcp flags syn / fin,syn,rst,ack tcp option sack-perm exists counter name sackpermc - tcp flags syn / fin,syn,rst,ack tcp option maxseg size gt 1400 counter name maxsegc - tcp flags syn / fin,syn,rst,ack tcp option nop missing counter name nomatchc - tcp flags syn / fin,syn,rst,ack tcp option nop exists counter name nopc - tcp flags syn / fin,syn,rst,ack drop + tcp flags & (fin | syn | rst | ack ) == syn tcp option 254 length ge 4 counter name nomatchc drop + tcp flags & (fin | syn | rst | ack ) == syn tcp option fastopen length ge 2 reset tcp option fastopen counter name nomatchc + tcp flags & (fin | syn | rst | ack ) == syn tcp option sack-perm missing counter name nomatchc + tcp flags & (fin | syn | rst | ack) == syn tcp option sack-perm exists counter name sackpermc + tcp flags & (fin | syn | rst | ack) == syn tcp option maxseg size gt 1400 counter name maxsegc + tcp flags & (fin | syn | rst | ack) == syn tcp option nop missing counter name nomatchc + tcp flags & (fin | syn | rst | ack) == syn tcp option nop exists counter name nopc + tcp flags & (fin | syn | rst | ack) == syn drop } } EOF -- 2.30.2