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 /net | |
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>
Diffstat (limited to 'net')
-rw-r--r-- | net/netfilter/xt_recent.c | 28 |
1 files changed, 27 insertions, 1 deletions
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 " |