netfilter: nft_meta: support for time matching
authorAnder Juaristi <a@juaristi.eus>
Sat, 17 Aug 2019 11:17:53 +0000 (13:17 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Mon, 26 Aug 2019 09:03:14 +0000 (11:03 +0200)
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.

Signed-off-by: Ander Juaristi <a@juaristi.eus>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
include/uapi/linux/netfilter/nf_tables.h
net/netfilter/nft_meta.c

index 82abaa1..b83b62e 100644 (file)
@@ -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_NS: time since epoch (in nanoseconds)
+ * @NFT_META_TIME_DAY: day of week (from 0 = Sunday to 6 = Saturday)
+ * @NFT_META_TIME_HOUR: hour of day (in seconds)
  */
 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_NS,
+       NFT_META_TIME_DAY,
+       NFT_META_TIME_HOUR,
 };
 
 /**
index f69afb9..317e3a9 100644 (file)
 
 #include <uapi/linux/netfilter_bridge.h> /* NF_BR_PRE_ROUTING */
 
+#define NFT_META_SECS_PER_MINUTE       60
+#define NFT_META_SECS_PER_HOUR         3600
+#define NFT_META_SECS_PER_DAY          86400
+#define NFT_META_DAYS_PER_WEEK         7
+
 static DEFINE_PER_CPU(struct rnd_state, nft_prandom_state);
 
+static u8 nft_meta_weekday(unsigned long secs)
+{
+       unsigned int dse;
+       u8 wday;
+
+       secs -= NFT_META_SECS_PER_MINUTE * sys_tz.tz_minuteswest;
+       dse = secs / NFT_META_SECS_PER_DAY;
+       wday = (4 + dse) % NFT_META_DAYS_PER_WEEK;
+
+       return wday;
+}
+
+static u32 nft_meta_hour(unsigned long secs)
+{
+       struct tm tm;
+
+       time64_to_tm(secs, 0, &tm);
+
+       return tm.tm_hour * NFT_META_SECS_PER_HOUR
+               + tm.tm_min * NFT_META_SECS_PER_MINUTE
+               + tm.tm_sec;
+}
+
 void nft_meta_get_eval(const struct nft_expr *expr,
                       struct nft_regs *regs,
                       const struct nft_pktinfo *pkt)
@@ -218,6 +246,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_NS:
+               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;
@@ -330,6 +367,15 @@ int nft_meta_get_init(const struct nft_ctx *ctx,
                len = sizeof(u8);
                break;
 #endif
+       case NFT_META_TIME_NS:
+               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;
        }