Ander Juaristi <[email protected]> wrote:
> 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.
>
> 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 "Sat" drop;
> day 6 drop;
> hour >= 17:00 drop;
> hour >= "17:00:01" drop;
> hour >= 63000 drop;
>
> Signed-off-by: Ander Juaristi <[email protected]>
> ---
> include/datatype.h | 3 +
> include/linux/netfilter/nf_tables.h | 6 +
> include/meta.h | 3 +
> include/nftables.h | 5 +
> include/nftables/libnftables.h | 1 +
> src/datatype.c | 3 +
> src/main.c | 11 +-
> src/meta.c | 286 ++++++++++++++++++++++++++++
> src/parser_bison.y | 4 +
> src/scanner.l | 4 +-
> 10 files changed, 324 insertions(+), 2 deletions(-)
>
> diff --git a/include/datatype.h b/include/datatype.h
> index 63617eb..a102f3f 100644
> --- a/include/datatype.h
> +++ b/include/datatype.h
> @@ -90,6 +90,9 @@ enum datatypes {
> TYPE_CT_EVENTBIT,
> TYPE_IFNAME,
> TYPE_IGMP_TYPE,
> + TYPE_TIME_TYPE,
> + TYPE_HOUR_TYPE,
> + TYPE_DAY_TYPE,
> __TYPE_MAX
> };
> #define TYPE_MAX (__TYPE_MAX - 1)
> diff --git a/include/linux/netfilter/nf_tables.h
> b/include/linux/netfilter/nf_tables.h
> index 7bdb234..ce621ed 100644
> --- a/include/linux/netfilter/nf_tables.h
> +++ b/include/linux/netfilter/nf_tables.h
> @@ -793,6 +793,9 @@ enum nft_exthdr_attributes {
> * @NFT_META_SECPATH: boolean, secpath_exists (!!skb->sp)
> * @NFT_META_IIFKIND: packet input interface kind name
> (dev->rtnl_link_ops->kind)
> * @NFT_META_OIFKIND: packet output interface kind name
> (dev->rtnl_link_ops->kind)
> + * @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,
> @@ -823,6 +826,9 @@ enum nft_meta_keys {
> NFT_META_SECPATH,
> NFT_META_IIFKIND,
> NFT_META_OIFKIND,
> + NFT_META_TIME,
> + NFT_META_TIME_DAY,
> + NFT_META_TIME_HOUR,
> };
>
> /**
> diff --git a/include/meta.h b/include/meta.h
> index a49b4ff..a62a130 100644
> --- a/include/meta.h
> +++ b/include/meta.h
> @@ -41,6 +41,9 @@ extern const struct datatype uid_type;
> extern const struct datatype devgroup_type;
> extern const struct datatype pkttype_type;
> extern const struct datatype ifname_type;
> +extern const struct datatype date_type;
> +extern const struct datatype hour_type;
> +extern const struct datatype day_type;
>
> extern struct symbol_table *devgroup_tbl;
>
> diff --git a/include/nftables.h b/include/nftables.h
> index ed446e2..52aff12 100644
> --- a/include/nftables.h
> +++ b/include/nftables.h
> @@ -62,6 +62,11 @@ static inline bool nft_output_guid(const struct output_ctx
> *octx)
> return octx->flags & NFT_CTX_OUTPUT_GUID;
> }
>
> +static inline bool nft_output_seconds(const struct output_ctx *octx)
> +{
> + return octx->flags & NFT_CTX_OUTPUT_SECONDS;
> +}
> +
> static inline bool nft_output_numeric_proto(const struct output_ctx *octx)
> {
> return octx->flags & NFT_CTX_OUTPUT_NUMERIC_PROTO;
> diff --git a/include/nftables/libnftables.h b/include/nftables/libnftables.h
> index e39c588..87d4ff5 100644
> --- a/include/nftables/libnftables.h
> +++ b/include/nftables/libnftables.h
> @@ -52,6 +52,7 @@ enum {
> NFT_CTX_OUTPUT_NUMERIC_PROTO = (1 << 7),
> NFT_CTX_OUTPUT_NUMERIC_PRIO = (1 << 8),
> NFT_CTX_OUTPUT_NUMERIC_SYMBOL = (1 << 9),
> + NFT_CTX_OUTPUT_SECONDS = (1 << 10),
> NFT_CTX_OUTPUT_NUMERIC_ALL = (NFT_CTX_OUTPUT_NUMERIC_PROTO |
> NFT_CTX_OUTPUT_NUMERIC_PRIO |
> NFT_CTX_OUTPUT_NUMERIC_SYMBOL),
> diff --git a/src/datatype.c b/src/datatype.c
> index 6d6826e..2ee7a8f 100644
> --- a/src/datatype.c
> +++ b/src/datatype.c
> @@ -71,6 +71,9 @@ static const struct datatype *datatypes[TYPE_MAX + 1] = {
> [TYPE_BOOLEAN] = &boolean_type,
> [TYPE_IFNAME] = &ifname_type,
> [TYPE_IGMP_TYPE] = &igmp_type_type,
> + [TYPE_TIME_TYPE] = &date_type,
> + [TYPE_HOUR_TYPE] = &hour_type,
> + [TYPE_DAY_TYPE] = &day_type,
TYPE_FOO_TYPE looks weird, maybe use
TYPE_TIME_DATE
TYPE_TIME_HOUR
TYPE_TIME_DAY
?
> +static void day_type_print(const struct expr *expr, struct output_ctx *octx)
> +{
> + const char *days[] = {
> + "Sunday",
> + "Monday",
> + "Tuesday",
> + "Wednesday",
> + "Thursday",
> + "Friday",
> + "Saturday"
> + };
> + uint8_t daynum = mpz_get_uint8(expr->value),
> + numdays = sizeof(days) / (3 * 3);
numdays = array_size(days) ?
> +#define MIN(a, b) (a < b ? a : b)
There is min() in include/utils.h.
> + };
> + int daynum = -1, numdays = (sizeof(days) / 7) - 1;
numdays = array_size(days)
> +static void __hour_type_print_r(int hours, int minutes, int seconds, char
> *out)
> +{
> + if (minutes == 60)
> + return __hour_type_print_r(++hours, 0, seconds, out);
> + else if (minutes > 60)
> + return __hour_type_print_r((int) (minutes / 60), minutes % 60,
> seconds, out);
> +
> + if (seconds == 60)
> + return __hour_type_print_r(hours, ++minutes, 0, out);
> + else if (seconds > 60)
> + return __hour_type_print_r(hours, (int) (seconds / 60), seconds
> % 60, out);
> +
> + if (seconds == 0)
> + snprintf(out, 6, "%02d:%02d", hours, minutes);
> + else
> + snprintf(out, 9, "%02d:%02d:%02d", hours, minutes, seconds);
> +}
I think it would be preferrable to pass a size_t buflen here and use
that rather than the magic buffer sizes in snrintf().
> +const struct datatype date_type = {
> + .type = TYPE_TIME_TYPE,
> + .name = "time",
> + .desc = "Relative time of packet reception",
> + .byteorder = BYTEORDER_HOST_ENDIAN,
> + .size = 8 * BITS_PER_BYTE,
Probably better to use sizeof(uint64_t) * BITS_PER_BYTE here.
Otherwise this looks good to me. Once libnftnl support is ready and the
grammar accepted we also need an update to the documentation and a few
test cases for this. (in tests/py/ ).