diff options
author | Tim Gardner <tim.gardner@canonical.com> | 2010-03-16 14:53:13 -0400 |
---|---|---|
committer | Patrick McHardy <kaber@trash.net> | 2010-03-17 10:53:12 -0400 |
commit | 0079c5aee34880bcee7feee9960f0502c73dc5fa (patch) | |
tree | a828b04c52f6650cbd654ca7b7de5ccdab5762c7 | |
parent | 5be4a4f589841ef06fd79b241de3d5353a6c5efa (diff) |
netfilter: xt_recent: add an entry reaper
One of the problems with the way xt_recent is implemented is that
there is no efficient way to remove expired entries. Of course,
one can write a rule '-m recent --remove', but you have to know
beforehand which entry to delete. This commit adds reaper
logic which checks the head of the LRU list when a rule
is invoked that has a '--seconds' value and XT_RECENT_REAP set. If an
entry ceases to accumulate time stamps, then it will eventually bubble
to the top of the LRU list where it is then reaped.
Signed-off-by: Tim Gardner <tim.gardner@canonical.com>
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: Patrick McHardy <kaber@trash.net>
-rw-r--r-- | include/linux/netfilter/xt_recent.h | 4 | ||||
-rw-r--r-- | net/netfilter/xt_recent.c | 28 |
2 files changed, 31 insertions, 1 deletions
diff --git a/include/linux/netfilter/xt_recent.h b/include/linux/netfilter/xt_recent.h index d2c276609925..bba990ecb018 100644 --- a/include/linux/netfilter/xt_recent.h +++ b/include/linux/netfilter/xt_recent.h | |||
@@ -9,6 +9,7 @@ enum { | |||
9 | XT_RECENT_UPDATE = 1 << 2, | 9 | XT_RECENT_UPDATE = 1 << 2, |
10 | XT_RECENT_REMOVE = 1 << 3, | 10 | XT_RECENT_REMOVE = 1 << 3, |
11 | XT_RECENT_TTL = 1 << 4, | 11 | XT_RECENT_TTL = 1 << 4, |
12 | XT_RECENT_REAP = 1 << 5, | ||
12 | 13 | ||
13 | XT_RECENT_SOURCE = 0, | 14 | XT_RECENT_SOURCE = 0, |
14 | XT_RECENT_DEST = 1, | 15 | XT_RECENT_DEST = 1, |
@@ -16,6 +17,9 @@ enum { | |||
16 | XT_RECENT_NAME_LEN = 200, | 17 | XT_RECENT_NAME_LEN = 200, |
17 | }; | 18 | }; |
18 | 19 | ||
20 | /* Only allowed with --rcheck and --update */ | ||
21 | #define XT_RECENT_MODIFIERS (XT_RECENT_TTL|XT_RECENT_REAP) | ||
22 | |||
19 | struct xt_recent_mtinfo { | 23 | struct xt_recent_mtinfo { |
20 | __u32 seconds; | 24 | __u32 seconds; |
21 | __u32 hit_count; | 25 | __u32 hit_count; |
diff --git a/net/netfilter/xt_recent.c b/net/netfilter/xt_recent.c index 2ff8aae84a38..b65eca9e13a3 100644 --- a/net/netfilter/xt_recent.c +++ b/net/netfilter/xt_recent.c | |||
@@ -143,6 +143,25 @@ static void recent_entry_remove(struct recent_table *t, struct recent_entry *e) | |||
143 | t->entries--; | 143 | t->entries--; |
144 | } | 144 | } |
145 | 145 | ||
146 | /* | ||
147 | * Drop entries with timestamps older then 'time'. | ||
148 | */ | ||
149 | static void recent_entry_reap(struct recent_table *t, unsigned long time) | ||
150 | { | ||
151 | struct recent_entry *e; | ||
152 | |||
153 | /* | ||
154 | * The head of the LRU list is always the oldest entry. | ||
155 | */ | ||
156 | e = list_entry(t->lru_list.next, struct recent_entry, lru_list); | ||
157 | |||
158 | /* | ||
159 | * The last time stamp is the most recent. | ||
160 | */ | ||
161 | if (time_after(time, e->stamps[e->index-1])) | ||
162 | recent_entry_remove(t, e); | ||
163 | } | ||
164 | |||
146 | static struct recent_entry * | 165 | static struct recent_entry * |
147 | recent_entry_init(struct recent_table *t, const union nf_inet_addr *addr, | 166 | recent_entry_init(struct recent_table *t, const union nf_inet_addr *addr, |
148 | u_int16_t family, u_int8_t ttl) | 167 | u_int16_t family, u_int8_t ttl) |
@@ -269,6 +288,10 @@ recent_mt(const struct sk_buff *skb, const struct xt_match_param *par) | |||
269 | break; | 288 | break; |
270 | } | 289 | } |
271 | } | 290 | } |
291 | |||
292 | /* info->seconds must be non-zero */ | ||
293 | if (info->check_set & XT_RECENT_REAP) | ||
294 | recent_entry_reap(t, time); | ||
272 | } | 295 | } |
273 | 296 | ||
274 | if (info->check_set & XT_RECENT_SET || | 297 | if (info->check_set & XT_RECENT_SET || |
@@ -301,7 +324,10 @@ static bool recent_mt_check(const struct xt_mtchk_param *par) | |||
301 | XT_RECENT_CHECK | XT_RECENT_UPDATE)) != 1) | 324 | XT_RECENT_CHECK | XT_RECENT_UPDATE)) != 1) |
302 | return false; | 325 | return false; |
303 | if ((info->check_set & (XT_RECENT_SET | XT_RECENT_REMOVE)) && | 326 | if ((info->check_set & (XT_RECENT_SET | XT_RECENT_REMOVE)) && |
304 | (info->seconds || info->hit_count)) | 327 | (info->seconds || info->hit_count || |
328 | (info->check_set & XT_RECENT_MODIFIERS))) | ||
329 | return false; | ||
330 | if ((info->check_set & XT_RECENT_REAP) && !info->seconds) | ||
305 | return false; | 331 | return false; |
306 | if (info->hit_count > ip_pkt_list_tot) { | 332 | if (info->hit_count > ip_pkt_list_tot) { |
307 | pr_info(KBUILD_MODNAME ": hitcount (%u) is larger than " | 333 | pr_info(KBUILD_MODNAME ": hitcount (%u) is larger than " |