f8f32deda31d ("meta: Introduce new conditions 'time', 'day' and 'hour'") reverses the hour range in case that a cross-day range is used, eg. meta hour "03:01"-"08:00" counter accept which results in (Sidney, Australia AEDT time): meta hour != "14:00"-"03:00" counter accept from the list ruleset path, which not very intuitive to the reader. Complete netlink delinearize path to reverse the cross-day meta range. Note that kernel handles time in UTC, therefore, cross-day range may not be look according to local time. Update manpage to recommend to use a range expression when matching meta hour range. While at it, update manpage to recommend to use a range with meta time and meta day too. Closes: https://bugzilla.netfilter.org/show_bug.cgi?id=1737 Signed-off-by: Pablo Neira Ayuso <pablo@xxxxxxxxxxxxx> --- doc/primary-expression.txt | 12 +++++++++--- include/expression.h | 1 + include/meta.h | 2 ++ src/evaluate.c | 8 ++++---- src/netlink_delinearize.c | 22 ++++++++++++++++++++++ 5 files changed, 38 insertions(+), 7 deletions(-) diff --git a/doc/primary-expression.txt b/doc/primary-expression.txt index e13970cfb650..782494bda6f3 100644 --- a/doc/primary-expression.txt +++ b/doc/primary-expression.txt @@ -168,15 +168,18 @@ Either an integer or a date in ISO format. For example: "2019-06-06 17:00". Hour and seconds are optional and can be omitted if desired. If omitted, midnight will be assumed. The following three would be equivalent: "2019-06-06", "2019-06-06 00:00" -and "2019-06-06 00:00:00". +and "2019-06-06 00:00:00". Use a range expression such as +"2019-06-06 10:00"-"2019-06-10 14:00" for matching a time range. When an integer is given, it is assumed to be a UNIX timestamp. |day| Either a day of week ("Monday", "Tuesday", etc.), or an integer between 0 and 6. Strings are matched case-insensitively, and a full match is not expected (e.g. "Mon" would match "Monday"). -When an integer is given, 0 is Sunday and 6 is Saturday. +When an integer is given, 0 is Sunday and 6 is Saturday. Use a range expression +such as "Monday"-"Wednesday" for matching a week day range. |hour| A string representing an hour in 24-hour format. Seconds can optionally be specified. -For example, 17:00 and 17:00:00 would be equivalent. +For example, 17:00 and 17:00:00 would be equivalent. Use a range expression such +as "17:00"-"19:00" for matching a time range. |============================= .Using meta expressions @@ -190,6 +193,9 @@ filter output oif eth0 # incoming packet was subject to ipsec processing raw prerouting meta ipsec exists accept + +# match incoming packet from 03:00 to 14:00 local time +raw prerouting meta hour "03:00"-"14:00" counter accept ----------------------- SOCKET EXPRESSION diff --git a/include/expression.h b/include/expression.h index f5d7e160a9aa..01b45b7c83b9 100644 --- a/include/expression.h +++ b/include/expression.h @@ -530,5 +530,6 @@ struct expr *flagcmp_expr_alloc(const struct location *loc, enum ops op, extern void range_expr_value_low(mpz_t rop, const struct expr *expr); extern void range_expr_value_high(mpz_t rop, const struct expr *expr); +void range_expr_swap_values(struct expr *range); #endif /* NFTABLES_EXPRESSION_H */ diff --git a/include/meta.h b/include/meta.h index 1478902ed141..af2d772bb6a0 100644 --- a/include/meta.h +++ b/include/meta.h @@ -45,4 +45,6 @@ extern const struct datatype date_type; extern const struct datatype hour_type; extern const struct datatype day_type; +bool lhs_is_meta_hour(const struct expr *meta); + #endif /* NFTABLES_META_H */ diff --git a/src/evaluate.c b/src/evaluate.c index 5b585714180d..e3ead3329636 100644 --- a/src/evaluate.c +++ b/src/evaluate.c @@ -2470,7 +2470,7 @@ static int binop_transfer(struct eval_ctx *ctx, struct expr **expr) return 0; } -static bool lhs_is_meta_hour(const struct expr *meta) +bool lhs_is_meta_hour(const struct expr *meta) { if (meta->etype != EXPR_META) return false; @@ -2479,7 +2479,7 @@ static bool lhs_is_meta_hour(const struct expr *meta) meta->meta.key == NFT_META_TIME_DAY; } -static void swap_values(struct expr *range) +void range_expr_swap_values(struct expr *range) { struct expr *left_tmp; @@ -2561,10 +2561,10 @@ static int expr_evaluate_relational(struct eval_ctx *ctx, struct expr **expr) "Inverting range values for cross-day hour matching\n\n"); if (rel->op == OP_EQ || rel->op == OP_IMPLICIT) { - swap_values(range); + range_expr_swap_values(range); rel->op = OP_NEQ; } else if (rel->op == OP_NEQ) { - swap_values(range); + range_expr_swap_values(range); rel->op = OP_EQ; } } diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c index 405a065bc98f..5a4cf1b88110 100644 --- a/src/netlink_delinearize.c +++ b/src/netlink_delinearize.c @@ -2847,6 +2847,28 @@ static void expr_postprocess(struct rule_pp_ctx *ctx, struct expr **exprp) expr_postprocess(ctx, &expr->left); ctx->set = NULL; break; + case EXPR_UNARY: + if (lhs_is_meta_hour(expr->left->arg) && + expr->right->etype == EXPR_RANGE) { + struct expr *range = expr->right; + + /* Cross-day range needs to be reversed. + * Kernel handles time in UTC. Therefore, + * 03:00-14:00 AEDT (Sidney, Australia) time + * is a cross-day range. + */ + if (mpz_cmp(range->left->value, + range->right->value) <= 0) { + if (expr->op == OP_NEQ) { + range_expr_swap_values(range); + expr->op = OP_IMPLICIT; + } else if (expr->op == OP_IMPLICIT) { + range_expr_swap_values(range); + expr->op = OP_NEG; + } + } + } + /* fallthrough */ default: expr_postprocess(ctx, &expr->left); break; -- 2.30.2