From: Patrick McHardy <kaber@trash.net>
To: Jan Engelhardt <jengelh@computergmbh.de>
Cc: Netfilter Developer Mailing List <netfilter-devel@vger.kernel.org>
Subject: Re: xt_time 2007-09-22
Date: Sat, 22 Sep 2007 17:19:31 +0200 [thread overview]
Message-ID: <46F53283.90204@trash.net> (raw)
In-Reply-To: <Pine.LNX.4.64.0709221315590.15712@fbirervta.pbzchgretzou.qr>
Jan Engelhardt wrote:
> +/*
> + * Each network packet has a (nano)seconds-since-the-epoch (SSTE) timestamp.
> + * Since we match against days and daytime, the SSTE value needs to be
> + * computed back into human-readable dates.
> + *
> + * This is done in three separate functions so that the most expensive
> + * calculations are done last, in case a "simple match" can be found earlier.
> + */
> +static inline unsigned int localtime_1(struct xtm *r, time_t time)
> +{
> + unsigned int v, w;
> +
> + /* Each day has 86400s, so finding the hour/minute is actually easy. */
> + v = time % 86400;
> + r->second = v % 60;
> + w = v / 60;
> + r->minute = w % 60;
> + r->hour = w / 60;
> + return v;
> +}
> +
> +static inline void localtime_2(struct xtm *r, time_t time)
> +{
> + /*
> + * Here comes the rest (weekday, monthday). First, divide the SSTE
> + * by seconds-per-day to get the number of _days_ since the epoch.
> + */
> + r->dse = time / 86400;
> +
> + /* 1970-01-01 (w=0) was a Thursday (4). */
> + r->weekday = (4 + r->dse) % 7;
> +}
> +
> +static void localtime_3(struct xtm *r, time_t time)
> +{
> + unsigned int year, i, w = r->dse;
> +
> + /*
> + * In each year, a certain number of days-since-the-epoch have passed.
> + * Find the year that is closest to said days.
> + *
> + * Consider, for example, w=21612 (2029-03-04). Loop will abort on
> + * dse[i] <= w, which happens when dse[i] == 21550. This implies
> + * year == 2009. w will then be 62.
> + */
> + for (i = 0, year = DSE_FIRST; days_since_epoch[i] > w;
> + ++i, --year)
> + /* just loop */;
> +
> + w -= days_since_epoch[i];
> +
> + /*
> + * By now we have the current year, and the day of the year.
> + * r->yearday = w;
> + *
> + * On to finding the month (like above). In each month, a certain
> + * number of days-since-New Year have passed, and find the closest
> + * one.
> + *
> + * Consider w=62 (in a non-leap year). Loop will abort on
> + * dsy[i] < w, which happens when dsy[i] == 31+28 (i == 2).
> + * Concludes i == 2, i.e. 3rd month => March.
> + *
> + * (A different approach to use would be to subtract a monthlength
> + * from w repeatedly while counting.)
> + */
> + if (is_leap(year)) {
> + for (i = ARRAY_SIZE(days_since_leapyear) - 1;
> + i > 0 && days_since_year[i] > w; --i)
> + /* just loop */;
> + } else {
> + for (i = ARRAY_SIZE(days_since_year) - 1;
> + i > 0 && days_since_year[i] > w; --i)
> + /* just loop */;
> + }
> +
> + r->month = i + 1;
> + r->monthday = w - days_since_year[i] + 1;
> + return;
> +}
>
A thought just occured to me (a bit late, but better than never :) ..
Can't we just convert the user-specified times/dates to unix time
and match on that without all these expensive calculations? At least
for pure time matching without days this should work fine ..
> +
> +static bool xt_time_match(const struct sk_buff *skb,
> + const struct net_device *in,
> + const struct net_device *out,
> + const struct xt_match *match, const void *matchinfo,
> + int offset, unsigned int protoff, bool *hotdrop)
> +{
> + const struct xt_time_info *info = matchinfo;
> + unsigned int packet_time;
> + struct xtm current_time;
> + s64 stamp;
> +
> + /*
> + * We cannot use get_seconds() instead of __net_timestamp() here.
> + * Suppose you have two rules:
> + * 1. match before 13:00
> + * 2. match after 13:00
> + * If you match against processing time (get_seconds) it
> + * may happen that the same packet matches both rules if
> + * it arrived at the right moment before 13:00.
> + */
> + if (skb->tstamp.tv64 == 0)
> + __net_timestamp((struct sk_buff *)skb);
> +
> + stamp = skb->tstamp.tv64;
> + do_div(stamp, NSEC_PER_SEC);
> +
> + if (info->flags & XT_TIME_LOCAL_TZ)
> + /* Adjust for local timezone */
> + stamp -= 60 * sys_tz.tz_minuteswest;
> +
> + /*
> + * xt_time will match when _all_ of the following hold:
> + * - 'now' is in the global time range date_start..date_end
> + * - 'now' is in the monthday mask
> + * - 'now' is in the weekday mask
> + * - 'now' is in the daytime range time_start..time_end
> + * (and by default, libxt_time will set these so as to match)
> + */
> +
> + if (stamp < info->date_start || stamp > info->date_stop)
> + return false;
> +
> + packet_time = localtime_1(¤t_time, stamp);
> +
> + if (info->daytime_start < info->daytime_stop) {
> + if (packet_time < info->daytime_start ||
> + packet_time > info->daytime_stop)
> + return false;
> + } else {
> + if (packet_time < info->daytime_start &&
> + packet_time > info->daytime_stop)
> + return false;
> + }
> +
> + localtime_2(¤t_time, stamp);
> +
> + if (!(info->weekdays_match & (1 << current_time.weekday)))
> + return false;
> +
> + localtime_3(¤t_time, stamp);
> +
> + if (!(info->monthdays_match & (1 << current_time.monthday)))
> + return false;
>
I'd add a flag or check whether weekdays_match/monthdays_match
equals ~0 before doing the localtime calculations.
Besides that, looks good to me, thanks for doing this work.
next prev parent reply other threads:[~2007-09-22 15:21 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-09-22 11:26 xt_time 2007-09-22 Jan Engelhardt
2007-09-22 11:28 ` xt_time 2007-09-22 (iptables) Jan Engelhardt
2007-09-23 15:08 ` Patrick McHardy
2007-09-22 15:19 ` Patrick McHardy [this message]
2007-09-22 15:38 ` xt_time 2007-09-22 Jan Engelhardt
2007-09-22 15:39 ` Patrick McHardy
2007-09-22 15:47 ` Jan Engelhardt
2007-09-22 15:58 ` Jan Engelhardt
2007-09-23 15:05 ` Patrick McHardy
2007-09-23 15:32 ` Jan Engelhardt
2007-09-23 16:20 ` Patrick McHardy
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=46F53283.90204@trash.net \
--to=kaber@trash.net \
--cc=jengelh@computergmbh.de \
--cc=netfilter-devel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).