This patch introduces meta matches in the kernel for time (a UNIX timestamp),
day (a day of week, represented as an integer between 0-6), and
hour (an hour in the current day, or: number of seconds since midnight).

All values are taken as unsigned 64-bit integers.

The 'time' keyword is internally converted to nanoseconds by nft in
userspace, and hence the timestamp is taken in nanoseconds as well.

This patch also introduces a new function, nft_reg_store64, to store
64-bit values in the register for comparison.

Signed-off-by: Ander Juaristi <a...@juaristi.eus>
---
 include/uapi/linux/netfilter/nf_tables.h |  6 ++++
 net/netfilter/nft_meta.c                 | 39 ++++++++++++++++++++++++
 2 files changed, 45 insertions(+)

diff --git a/include/uapi/linux/netfilter/nf_tables.h 
b/include/uapi/linux/netfilter/nf_tables.h
index 82abaa183fc3..67ae55e08518 100644
--- a/include/uapi/linux/netfilter/nf_tables.h
+++ b/include/uapi/linux/netfilter/nf_tables.h
@@ -799,6 +799,9 @@ enum nft_exthdr_attributes {
  * @NFT_META_OIFKIND: packet output interface kind name 
(dev->rtnl_link_ops->kind)
  * @NFT_META_BRI_IIFPVID: packet input bridge port pvid
  * @NFT_META_BRI_IIFVPROTO: packet input bridge vlan proto
+ * @NFT_META_TIME: a UNIX timestamp
+ * @NFT_META_TIME_DAY: day of week
+ * @NFT_META_TIME_HOUR: hour of day
  */
 enum nft_meta_keys {
        NFT_META_LEN,
@@ -831,6 +834,9 @@ enum nft_meta_keys {
        NFT_META_OIFKIND,
        NFT_META_BRI_IIFPVID,
        NFT_META_BRI_IIFVPROTO,
+       NFT_META_TIME,
+       NFT_META_TIME_DAY,
+       NFT_META_TIME_HOUR,
 };
 
 /**
diff --git a/net/netfilter/nft_meta.c b/net/netfilter/nft_meta.c
index f1b1d948c07b..3e665a1a744a 100644
--- a/net/netfilter/nft_meta.c
+++ b/net/netfilter/nft_meta.c
@@ -28,6 +28,27 @@
 
 static DEFINE_PER_CPU(struct rnd_state, nft_prandom_state);
 
+static u8 nft_meta_weekday(unsigned long secs)
+{
+       u8 wday;
+       unsigned int dse;
+
+       secs -= 60 * sys_tz.tz_minuteswest;
+       dse = secs / 86400;
+       wday = (4 + dse) % 7;
+
+       return wday;
+}
+
+static u32 nft_meta_hour(unsigned long secs)
+{
+       struct tm tm;
+
+       time64_to_tm(secs, 0, &tm);
+
+       return tm.tm_hour * 3600 + tm.tm_min * 60 + tm.tm_sec;
+}
+
 void nft_meta_get_eval(const struct nft_expr *expr,
                       struct nft_regs *regs,
                       const struct nft_pktinfo *pkt)
@@ -226,6 +247,15 @@ void nft_meta_get_eval(const struct nft_expr *expr,
                        goto err;
                strncpy((char *)dest, out->rtnl_link_ops->kind, IFNAMSIZ);
                break;
+       case NFT_META_TIME:
+               nft_reg_store64(dest, ktime_get_real_ns());
+               break;
+       case NFT_META_TIME_DAY:
+               nft_reg_store8(dest, nft_meta_weekday(get_seconds()));
+               break;
+       case NFT_META_TIME_HOUR:
+               *dest = nft_meta_hour(get_seconds());
+               break;
        default:
                WARN_ON(1);
                goto err;
@@ -338,6 +368,15 @@ int nft_meta_get_init(const struct nft_ctx *ctx,
                len = sizeof(u8);
                break;
 #endif
+       case NFT_META_TIME:
+               len = sizeof(u64);
+               break;
+       case NFT_META_TIME_DAY:
+               len = sizeof(u8);
+               break;
+       case NFT_META_TIME_HOUR:
+               len = sizeof(u32);
+               break;
        default:
                return -EOPNOTSUPP;
        }
-- 
2.17.1

Reply via email to