]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
meta: fix hour decoding when timezone offset is negative
authorFlorian Westphal <fw@strlen.de>
Thu, 2 Nov 2023 14:34:13 +0000 (15:34 +0100)
committerFlorian Westphal <fw@strlen.de>
Thu, 2 Nov 2023 22:33:01 +0000 (23:33 +0100)
Brian Davidson says:

 meta hour rules don't display properly after being created when the
 hour is on or after 00:00 UTC. The netlink debug looks correct for
 seconds past midnight UTC, but displaying the rules looks like an
 overflow or a byte order problem. I am in UTC-0400, so today, 20:00
 and later exhibits the problem, while 19:00 and earlier hours are
 fine.

meta.c only ever worked when the delta to UTC is positive.
We need to add in case the second counter turns negative after
offset adjustment.

Also add a test case for this.

Fixes: f8f32deda31d ("meta: Introduce new conditions 'time', 'day' and 'hour'")
Reported-by: Brian Davidson <davidson.brian@gmail.com>
Signed-off-by: Florian Westphal <fw@strlen.de>
src/meta.c
tests/shell/testcases/listing/dumps/meta_time.nodump [new file with mode: 0644]
tests/shell/testcases/listing/meta_time [new file with mode: 0755]

index b578d5e24c067a3de344e6703b1433d8c198bfb7..7846aefe7f5dff7eba03cdf7b3d05e970e7ab7e1 100644 (file)
@@ -495,9 +495,16 @@ static void hour_type_print(const struct expr *expr, struct output_ctx *octx)
 
        /* Obtain current tm, so that we can add tm_gmtoff */
        ts = time(NULL);
-       if (ts != ((time_t) -1) && localtime_r(&ts, &cur_tm))
-               seconds = (seconds + cur_tm.tm_gmtoff) % SECONDS_PER_DAY;
+       if (ts != ((time_t) -1) && localtime_r(&ts, &cur_tm)) {
+               int32_t adj = seconds + cur_tm.tm_gmtoff;
 
+               if (adj < 0)
+                       adj += SECONDS_PER_DAY;
+               else if (adj >= SECONDS_PER_DAY)
+                       adj -= SECONDS_PER_DAY;
+
+               seconds = adj;
+       }
        minutes = seconds / 60;
        seconds %= 60;
        hours = minutes / 60;
diff --git a/tests/shell/testcases/listing/dumps/meta_time.nodump b/tests/shell/testcases/listing/dumps/meta_time.nodump
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/shell/testcases/listing/meta_time b/tests/shell/testcases/listing/meta_time
new file mode 100755 (executable)
index 0000000..a976199
--- /dev/null
@@ -0,0 +1,52 @@
+#!/bin/bash
+
+set -e
+
+TMP1=$(mktemp)
+TMP2=$(mktemp)
+
+cleanup()
+{
+       rm -f "$TMP1"
+       rm -f "$TMP2"
+}
+
+check_decode()
+{
+       TZ=$1 $NFT list chain t c | grep meta > "$TMP2"
+       diff -u "$TMP1" "$TMP2"
+}
+
+trap cleanup EXIT
+
+$NFT -f - <<EOF
+table t {
+       chain c {
+       }
+}
+EOF
+
+for i in $(seq -w 0 23); do
+       TZ=UTC $NFT add rule t c meta hour "$i:00"-"$i:59"
+done
+
+# Check decoding in UTC, this mirrors 1:1 what should have been added.
+for i in $(seq 0 23); do
+       printf "\t\tmeta hour \"%02d:%02d\"-\"%02d:%02d\"\n" $i 0 $i 59 >> "$TMP1"
+done
+
+check_decode UTC
+
+printf "\t\tmeta hour \"%02d:%02d\"-\"%02d:%02d\"\n" 23 0 23 59 > "$TMP1"
+for i in $(seq 0 22); do
+       printf "\t\tmeta hour \"%02d:%02d\"-\"%02d:%02d\"\n" $i 0 $i 59 >> "$TMP1"
+done
+check_decode UTC+1
+
+printf "\t\tmeta hour \"%02d:%02d\"-\"%02d:%02d\"\n" 1 0 1 59 > "$TMP1"
+for i in $(seq 2 23); do
+       printf "\t\tmeta hour \"%02d:%02d\"-\"%02d:%02d\"\n" $i 0 $i 59 >> "$TMP1"
+done
+printf "\t\tmeta hour \"%02d:%02d\"-\"%02d:%02d\"\n" 0 0 0 59 >> "$TMP1"
+
+check_decode UTC-1