All of lore.kernel.org
 help / color / mirror / Atom feed
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(&current_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(&current_time, stamp);
> +
> +	if (!(info->weekdays_match & (1 << current_time.weekday)))
> +		return false;
> +
> +	localtime_3(&current_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.

  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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.