diff options
author | Jan Engelhardt <jengelh@computergmbh.de> | 2007-09-28 17:46:43 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2007-10-10 19:53:40 -0400 |
commit | ee4411a1b1e0b679c99686629b5eab5a072ce49f (patch) | |
tree | 3d8e317c2207da074af5d3c57367d95ebb537efc /net/netfilter | |
parent | 6b6ec99a03601aba0419f34e17630f7aa8d68e5f (diff) |
[NETFILTER]: x_tables: add xt_time match
This is ipt_time from POM-ng enhanced by the following:
* xtables/ipv6 support
* second granularity for daytime
* day-of-month support (for example "match on the 15th of each month")
* match against UTC or local timezone
Signed-off-by: Jan Engelhardt <jengelh@computergmbh.de>
Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/netfilter')
-rw-r--r-- | net/netfilter/Kconfig | 14 | ||||
-rw-r--r-- | net/netfilter/Makefile | 1 | ||||
-rw-r--r-- | net/netfilter/xt_time.c | 269 |
3 files changed, 284 insertions, 0 deletions
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index 3599770a247..d7a600a5720 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig | |||
@@ -665,6 +665,20 @@ config NETFILTER_XT_MATCH_TCPMSS | |||
665 | 665 | ||
666 | To compile it as a module, choose M here. If unsure, say N. | 666 | To compile it as a module, choose M here. If unsure, say N. |
667 | 667 | ||
668 | config NETFILTER_XT_MATCH_TIME | ||
669 | tristate '"time" match support' | ||
670 | depends on NETFILTER_XTABLES | ||
671 | ---help--- | ||
672 | This option adds a "time" match, which allows you to match based on | ||
673 | the packet arrival time (at the machine which netfilter is running) | ||
674 | on) or departure time/date (for locally generated packets). | ||
675 | |||
676 | If you say Y here, try `iptables -m time --help` for | ||
677 | more information. | ||
678 | |||
679 | If you want to compile it as a module, say M here. | ||
680 | If unsure, say N. | ||
681 | |||
668 | config NETFILTER_XT_MATCH_U32 | 682 | config NETFILTER_XT_MATCH_U32 |
669 | tristate '"u32" match support' | 683 | tristate '"u32" match support' |
670 | depends on NETFILTER_XTABLES | 684 | depends on NETFILTER_XTABLES |
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile index 0c054bf2797..93c58f97383 100644 --- a/net/netfilter/Makefile +++ b/net/netfilter/Makefile | |||
@@ -73,6 +73,7 @@ obj-$(CONFIG_NETFILTER_XT_MATCH_SCTP) += xt_sctp.o | |||
73 | obj-$(CONFIG_NETFILTER_XT_MATCH_STATE) += xt_state.o | 73 | obj-$(CONFIG_NETFILTER_XT_MATCH_STATE) += xt_state.o |
74 | obj-$(CONFIG_NETFILTER_XT_MATCH_STATISTIC) += xt_statistic.o | 74 | obj-$(CONFIG_NETFILTER_XT_MATCH_STATISTIC) += xt_statistic.o |
75 | obj-$(CONFIG_NETFILTER_XT_MATCH_STRING) += xt_string.o | 75 | obj-$(CONFIG_NETFILTER_XT_MATCH_STRING) += xt_string.o |
76 | obj-$(CONFIG_NETFILTER_XT_MATCH_TIME) += xt_time.o | ||
76 | obj-$(CONFIG_NETFILTER_XT_MATCH_TCPMSS) += xt_tcpmss.o | 77 | obj-$(CONFIG_NETFILTER_XT_MATCH_TCPMSS) += xt_tcpmss.o |
77 | obj-$(CONFIG_NETFILTER_XT_MATCH_PHYSDEV) += xt_physdev.o | 78 | obj-$(CONFIG_NETFILTER_XT_MATCH_PHYSDEV) += xt_physdev.o |
78 | obj-$(CONFIG_NETFILTER_XT_MATCH_U32) += xt_u32.o | 79 | obj-$(CONFIG_NETFILTER_XT_MATCH_U32) += xt_u32.o |
diff --git a/net/netfilter/xt_time.c b/net/netfilter/xt_time.c new file mode 100644 index 00000000000..ef48bbd9357 --- /dev/null +++ b/net/netfilter/xt_time.c | |||
@@ -0,0 +1,269 @@ | |||
1 | /* | ||
2 | * xt_time | ||
3 | * Copyright © Jan Engelhardt <jengelh@computergmbh.de>, 2007 | ||
4 | * | ||
5 | * based on ipt_time by Fabrice MARIE <fabrice@netfilter.org> | ||
6 | * This is a module which is used for time matching | ||
7 | * It is using some modified code from dietlibc (localtime() function) | ||
8 | * that you can find at http://www.fefe.de/dietlibc/ | ||
9 | * This file is distributed under the terms of the GNU General Public | ||
10 | * License (GPL). Copies of the GPL can be obtained from gnu.org/gpl. | ||
11 | */ | ||
12 | #include <linux/ktime.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/skbuff.h> | ||
15 | #include <linux/types.h> | ||
16 | #include <linux/netfilter/x_tables.h> | ||
17 | #include <linux/netfilter/xt_time.h> | ||
18 | |||
19 | struct xtm { | ||
20 | u_int8_t month; /* (1-12) */ | ||
21 | u_int8_t monthday; /* (1-31) */ | ||
22 | u_int8_t weekday; /* (1-7) */ | ||
23 | u_int8_t hour; /* (0-23) */ | ||
24 | u_int8_t minute; /* (0-59) */ | ||
25 | u_int8_t second; /* (0-59) */ | ||
26 | unsigned int dse; | ||
27 | }; | ||
28 | |||
29 | extern struct timezone sys_tz; /* ouch */ | ||
30 | |||
31 | static const u_int16_t days_since_year[] = { | ||
32 | 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, | ||
33 | }; | ||
34 | |||
35 | static const u_int16_t days_since_leapyear[] = { | ||
36 | 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, | ||
37 | }; | ||
38 | |||
39 | /* | ||
40 | * Since time progresses forward, it is best to organize this array in reverse, | ||
41 | * to minimize lookup time. | ||
42 | */ | ||
43 | enum { | ||
44 | DSE_FIRST = 2039, | ||
45 | }; | ||
46 | static const u_int16_t days_since_epoch[] = { | ||
47 | /* 2039 - 2030 */ | ||
48 | 25202, 24837, 24472, 24106, 23741, 23376, 23011, 22645, 22280, 21915, | ||
49 | /* 2029 - 2020 */ | ||
50 | 21550, 21184, 20819, 20454, 20089, 19723, 19358, 18993, 18628, 18262, | ||
51 | /* 2019 - 2010 */ | ||
52 | 17897, 17532, 17167, 16801, 16436, 16071, 15706, 15340, 14975, 14610, | ||
53 | /* 2009 - 2000 */ | ||
54 | 14245, 13879, 13514, 13149, 12784, 12418, 12053, 11688, 11323, 10957, | ||
55 | /* 1999 - 1990 */ | ||
56 | 10592, 10227, 9862, 9496, 9131, 8766, 8401, 8035, 7670, 7305, | ||
57 | /* 1989 - 1980 */ | ||
58 | 6940, 6574, 6209, 5844, 5479, 5113, 4748, 4383, 4018, 3652, | ||
59 | /* 1979 - 1970 */ | ||
60 | 3287, 2922, 2557, 2191, 1826, 1461, 1096, 730, 365, 0, | ||
61 | }; | ||
62 | |||
63 | static inline bool is_leap(unsigned int y) | ||
64 | { | ||
65 | return y % 4 == 0 && (y % 100 != 0 || y % 400 == 0); | ||
66 | } | ||
67 | |||
68 | /* | ||
69 | * Each network packet has a (nano)seconds-since-the-epoch (SSTE) timestamp. | ||
70 | * Since we match against days and daytime, the SSTE value needs to be | ||
71 | * computed back into human-readable dates. | ||
72 | * | ||
73 | * This is done in three separate functions so that the most expensive | ||
74 | * calculations are done last, in case a "simple match" can be found earlier. | ||
75 | */ | ||
76 | static inline unsigned int localtime_1(struct xtm *r, time_t time) | ||
77 | { | ||
78 | unsigned int v, w; | ||
79 | |||
80 | /* Each day has 86400s, so finding the hour/minute is actually easy. */ | ||
81 | v = time % 86400; | ||
82 | r->second = v % 60; | ||
83 | w = v / 60; | ||
84 | r->minute = w % 60; | ||
85 | r->hour = w / 60; | ||
86 | return v; | ||
87 | } | ||
88 | |||
89 | static inline void localtime_2(struct xtm *r, time_t time) | ||
90 | { | ||
91 | /* | ||
92 | * Here comes the rest (weekday, monthday). First, divide the SSTE | ||
93 | * by seconds-per-day to get the number of _days_ since the epoch. | ||
94 | */ | ||
95 | r->dse = time / 86400; | ||
96 | |||
97 | /* 1970-01-01 (w=0) was a Thursday (4). */ | ||
98 | r->weekday = (4 + r->dse) % 7; | ||
99 | } | ||
100 | |||
101 | static void localtime_3(struct xtm *r, time_t time) | ||
102 | { | ||
103 | unsigned int year, i, w = r->dse; | ||
104 | |||
105 | /* | ||
106 | * In each year, a certain number of days-since-the-epoch have passed. | ||
107 | * Find the year that is closest to said days. | ||
108 | * | ||
109 | * Consider, for example, w=21612 (2029-03-04). Loop will abort on | ||
110 | * dse[i] <= w, which happens when dse[i] == 21550. This implies | ||
111 | * year == 2009. w will then be 62. | ||
112 | */ | ||
113 | for (i = 0, year = DSE_FIRST; days_since_epoch[i] > w; | ||
114 | ++i, --year) | ||
115 | /* just loop */; | ||
116 | |||
117 | w -= days_since_epoch[i]; | ||
118 | |||
119 | /* | ||
120 | * By now we have the current year, and the day of the year. | ||
121 | * r->yearday = w; | ||
122 | * | ||
123 | * On to finding the month (like above). In each month, a certain | ||
124 | * number of days-since-New Year have passed, and find the closest | ||
125 | * one. | ||
126 | * | ||
127 | * Consider w=62 (in a non-leap year). Loop will abort on | ||
128 | * dsy[i] < w, which happens when dsy[i] == 31+28 (i == 2). | ||
129 | * Concludes i == 2, i.e. 3rd month => March. | ||
130 | * | ||
131 | * (A different approach to use would be to subtract a monthlength | ||
132 | * from w repeatedly while counting.) | ||
133 | */ | ||
134 | if (is_leap(year)) { | ||
135 | for (i = ARRAY_SIZE(days_since_leapyear) - 1; | ||
136 | i > 0 && days_since_year[i] > w; --i) | ||
137 | /* just loop */; | ||
138 | } else { | ||
139 | for (i = ARRAY_SIZE(days_since_year) - 1; | ||
140 | i > 0 && days_since_year[i] > w; --i) | ||
141 | /* just loop */; | ||
142 | } | ||
143 | |||
144 | r->month = i + 1; | ||
145 | r->monthday = w - days_since_year[i] + 1; | ||
146 | return; | ||
147 | } | ||
148 | |||
149 | static bool xt_time_match(const struct sk_buff *skb, | ||
150 | const struct net_device *in, | ||
151 | const struct net_device *out, | ||
152 | const struct xt_match *match, const void *matchinfo, | ||
153 | int offset, unsigned int protoff, bool *hotdrop) | ||
154 | { | ||
155 | const struct xt_time_info *info = matchinfo; | ||
156 | unsigned int packet_time; | ||
157 | struct xtm current_time; | ||
158 | s64 stamp; | ||
159 | |||
160 | /* | ||
161 | * We cannot use get_seconds() instead of __net_timestamp() here. | ||
162 | * Suppose you have two rules: | ||
163 | * 1. match before 13:00 | ||
164 | * 2. match after 13:00 | ||
165 | * If you match against processing time (get_seconds) it | ||
166 | * may happen that the same packet matches both rules if | ||
167 | * it arrived at the right moment before 13:00. | ||
168 | */ | ||
169 | if (skb->tstamp.tv64 == 0) | ||
170 | __net_timestamp((struct sk_buff *)skb); | ||
171 | |||
172 | stamp = skb->tstamp.tv64; | ||
173 | do_div(stamp, NSEC_PER_SEC); | ||
174 | |||
175 | if (info->flags & XT_TIME_LOCAL_TZ) | ||
176 | /* Adjust for local timezone */ | ||
177 | stamp -= 60 * sys_tz.tz_minuteswest; | ||
178 | |||
179 | /* | ||
180 | * xt_time will match when _all_ of the following hold: | ||
181 | * - 'now' is in the global time range date_start..date_end | ||
182 | * - 'now' is in the monthday mask | ||
183 | * - 'now' is in the weekday mask | ||
184 | * - 'now' is in the daytime range time_start..time_end | ||
185 | * (and by default, libxt_time will set these so as to match) | ||
186 | */ | ||
187 | |||
188 | if (stamp < info->date_start || stamp > info->date_stop) | ||
189 | return false; | ||
190 | |||
191 | packet_time = localtime_1(¤t_time, stamp); | ||
192 | |||
193 | if (info->daytime_start < info->daytime_stop) { | ||
194 | if (packet_time < info->daytime_start || | ||
195 | packet_time > info->daytime_stop) | ||
196 | return false; | ||
197 | } else { | ||
198 | if (packet_time < info->daytime_start && | ||
199 | packet_time > info->daytime_stop) | ||
200 | return false; | ||
201 | } | ||
202 | |||
203 | localtime_2(¤t_time, stamp); | ||
204 | |||
205 | if (!(info->weekdays_match & (1 << current_time.weekday))) | ||
206 | return false; | ||
207 | |||
208 | /* Do not spend time computing monthday if all days match anyway */ | ||
209 | if (info->monthdays_match != XT_TIME_ALL_MONTHDAYS) { | ||
210 | localtime_3(¤t_time, stamp); | ||
211 | if (!(info->monthdays_match & (1 << current_time.monthday))) | ||
212 | return false; | ||
213 | } | ||
214 | |||
215 | return true; | ||
216 | } | ||
217 | |||
218 | static bool xt_time_check(const char *tablename, const void *ip, | ||
219 | const struct xt_match *match, void *matchinfo, | ||
220 | unsigned int hook_mask) | ||
221 | { | ||
222 | struct xt_time_info *info = matchinfo; | ||
223 | |||
224 | if (info->daytime_start > XT_TIME_MAX_DAYTIME || | ||
225 | info->daytime_stop > XT_TIME_MAX_DAYTIME) { | ||
226 | printk(KERN_WARNING "xt_time: invalid argument - start or " | ||
227 | "stop time greater than 23:59:59\n"); | ||
228 | return false; | ||
229 | } | ||
230 | |||
231 | return true; | ||
232 | } | ||
233 | |||
234 | static struct xt_match xt_time_reg[] __read_mostly = { | ||
235 | { | ||
236 | .name = "time", | ||
237 | .family = AF_INET, | ||
238 | .match = xt_time_match, | ||
239 | .matchsize = sizeof(struct xt_time_info), | ||
240 | .checkentry = xt_time_check, | ||
241 | .me = THIS_MODULE, | ||
242 | }, | ||
243 | { | ||
244 | .name = "time", | ||
245 | .family = AF_INET6, | ||
246 | .match = xt_time_match, | ||
247 | .matchsize = sizeof(struct xt_time_info), | ||
248 | .checkentry = xt_time_check, | ||
249 | .me = THIS_MODULE, | ||
250 | }, | ||
251 | }; | ||
252 | |||
253 | static int __init xt_time_init(void) | ||
254 | { | ||
255 | return xt_register_matches(xt_time_reg, ARRAY_SIZE(xt_time_reg)); | ||
256 | } | ||
257 | |||
258 | static void __exit xt_time_exit(void) | ||
259 | { | ||
260 | xt_unregister_matches(xt_time_reg, ARRAY_SIZE(xt_time_reg)); | ||
261 | } | ||
262 | |||
263 | module_init(xt_time_init); | ||
264 | module_exit(xt_time_exit); | ||
265 | MODULE_AUTHOR("Jan Engelhardt <jengelh@computergmbh.de>"); | ||
266 | MODULE_DESCRIPTION("netfilter time match"); | ||
267 | MODULE_LICENSE("GPL"); | ||
268 | MODULE_ALIAS("ipt_time"); | ||
269 | MODULE_ALIAS("ip6t_time"); | ||