diff options
author | Ander Juaristi <a@juaristi.eus> | 2019-08-29 16:09:02 +0200 |
---|---|---|
committer | Florian Westphal <fw@strlen.de> | 2019-09-06 16:25:57 +0200 |
commit | f8f32deda31df597614d9f1f64ffb0c0320f4d54 (patch) | |
tree | 7e59bf617b39e30936521f000d9202b816472e04 /src/evaluate.c | |
parent | f521033afc41876173e6430cdd45fc07a1b76654 (diff) |
meta: Introduce new conditions 'time', 'day' and 'hour'
These keywords introduce new checks for a timestamp, an absolute date (which is converted to a timestamp),
an hour in the day (which is converted to the number of seconds since midnight) and a day of week.
When converting an ISO date (eg. 2019-06-06 17:00) to a timestamp,
we need to substract it the GMT difference in seconds, that is, the value
of the 'tm_gmtoff' field in the tm structure. This is because the kernel
doesn't know about time zones. And hence the kernel manages different timestamps
than those that are advertised in userspace when running, for instance, date +%s.
The same conversion needs to be done when converting hours (e.g 17:00) to seconds since midnight
as well.
The result needs to be computed modulo 86400 in case GMT offset (difference in seconds from UTC)
is negative.
We also introduce a new command line option (-t, --seconds) to show the actual
timestamps when printing the values, rather than the ISO dates, or the hour.
Some usage examples:
time < "2019-06-06 17:00" drop;
time < "2019-06-06 17:20:20" drop;
time < 12341234 drop;
day "Saturday" drop;
day 6 drop;
hour >= 17:00 drop;
hour >= "17:00:01" drop;
hour >= 63000 drop;
We need to convert an ISO date to a timestamp
without taking into account the time zone offset, since comparison will
be done in kernel space and there is no time zone information there.
Overwriting TZ is portable, but will cause problems when parsing a
ruleset that has 'time' and 'hour' rules. Parsing an 'hour' type must
not do time zone conversion, but that will be automatically done if TZ has
been overwritten to UTC.
Hence, we use timegm() to parse the 'time' type, even though it's not portable.
Overwriting TZ seems to be a much worse solution.
Finally, be aware that timestamps are converted to nanoseconds when
transferring to the kernel (as comparison is done with nanosecond
precision), and back to seconds when retrieving them for printing.
We swap left and right values in a range to properly handle
cross-day hour ranges (e.g. 23:15-03:22).
Signed-off-by: Ander Juaristi <a@juaristi.eus>
Reviewed-by: Florian Westphal <fw@strlen.de>
Diffstat (limited to 'src/evaluate.c')
-rw-r--r--[-rwxr-xr-x] | src/evaluate.c | 54 |
1 files changed, 54 insertions, 0 deletions
diff --git a/src/evaluate.c b/src/evaluate.c index a707f5e7..8d5f5f80 100755..100644 --- a/src/evaluate.c +++ b/src/evaluate.c @@ -1683,14 +1683,68 @@ static int binop_transfer(struct eval_ctx *ctx, struct expr **expr) return 0; } +static bool lhs_is_meta_hour(const struct expr *meta) +{ + if (meta->etype != EXPR_META) + return false; + + return meta->meta.key == NFT_META_TIME_HOUR || + meta->meta.key == NFT_META_TIME_DAY; +} + +static void swap_values(struct expr *range) +{ + struct expr *left_tmp; + + left_tmp = range->left; + range->left = range->right; + range->right = left_tmp; +} + +static bool range_needs_swap(const struct expr *range) +{ + const struct expr *right = range->right; + const struct expr *left = range->left; + + return mpz_cmp(left->value, right->value) > 0; +} + static int expr_evaluate_relational(struct eval_ctx *ctx, struct expr **expr) { struct expr *rel = *expr, *left, *right; + struct expr *range; + int ret; if (expr_evaluate(ctx, &rel->left) < 0) return -1; left = rel->left; + if (rel->right->etype == EXPR_RANGE && lhs_is_meta_hour(rel->left)) { + ret = __expr_evaluate_range(ctx, &rel->right); + if (ret) + return ret; + + range = rel->right; + + /* + * We may need to do this for proper cross-day ranges, + * e.g. meta hour 23:15-03:22 + */ + if (range_needs_swap(range)) { + if (ctx->nft->debug_mask & NFT_DEBUG_EVALUATION) + nft_print(&ctx->nft->output, + "Inverting range values for cross-day hour matching\n\n"); + + if (rel->op == OP_EQ || rel->op == OP_IMPLICIT) { + swap_values(range); + rel->op = OP_NEQ; + } else if (rel->op == OP_NEQ) { + swap_values(range); + rel->op = OP_EQ; + } + } + } + if (expr_evaluate(ctx, &rel->right) < 0) return -1; right = rel->right; |