diff options
author | Jan Engelhardt <jengelh@computergmbh.de> | 2008-10-08 05:35:00 -0400 |
---|---|---|
committer | Patrick McHardy <kaber@trash.net> | 2008-10-08 05:35:00 -0400 |
commit | e948b20a71a06a740c925d6ea22b59b4e17cfa0c (patch) | |
tree | 6298c43d1b6aa424c47e1dec8dfd3d932b813dcc /net/ipv4 | |
parent | 76108cea065cda58366d16a7eb6ca90d717a1396 (diff) |
netfilter: rename ipt_recent to xt_recent
Like with other modules (such as ipt_state), ipt_recent.h is changed
to forward definitions to (IOW include) xt_recent.h, and xt_recent.c
is changed to use the new constant names.
Signed-off-by: Jan Engelhardt <jengelh@medozas.de>
Signed-off-by: Patrick McHardy <kaber@trash.net>
Diffstat (limited to 'net/ipv4')
-rw-r--r-- | net/ipv4/netfilter/Kconfig | 13 | ||||
-rw-r--r-- | net/ipv4/netfilter/Makefile | 1 | ||||
-rw-r--r-- | net/ipv4/netfilter/ipt_recent.c | 501 |
3 files changed, 0 insertions, 515 deletions
diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index 90eb7cb47e7..4e842d56642 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig | |||
@@ -57,19 +57,6 @@ config IP_NF_IPTABLES | |||
57 | To compile it as a module, choose M here. If unsure, say N. | 57 | To compile it as a module, choose M here. If unsure, say N. |
58 | 58 | ||
59 | # The matches. | 59 | # The matches. |
60 | config IP_NF_MATCH_RECENT | ||
61 | tristate '"recent" match support' | ||
62 | depends on IP_NF_IPTABLES | ||
63 | depends on NETFILTER_ADVANCED | ||
64 | help | ||
65 | This match is used for creating one or many lists of recently | ||
66 | used addresses and then matching against that/those list(s). | ||
67 | |||
68 | Short options are available by using 'iptables -m recent -h' | ||
69 | Official Website: <http://snowman.net/projects/ipt_recent/> | ||
70 | |||
71 | To compile it as a module, choose M here. If unsure, say N. | ||
72 | |||
73 | config IP_NF_MATCH_ECN | 60 | config IP_NF_MATCH_ECN |
74 | tristate '"ecn" match support' | 61 | tristate '"ecn" match support' |
75 | depends on IP_NF_IPTABLES | 62 | depends on IP_NF_IPTABLES |
diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile index 3f31291f37c..1107edbe478 100644 --- a/net/ipv4/netfilter/Makefile +++ b/net/ipv4/netfilter/Makefile | |||
@@ -48,7 +48,6 @@ obj-$(CONFIG_IP_NF_SECURITY) += iptable_security.o | |||
48 | obj-$(CONFIG_IP_NF_MATCH_ADDRTYPE) += ipt_addrtype.o | 48 | obj-$(CONFIG_IP_NF_MATCH_ADDRTYPE) += ipt_addrtype.o |
49 | obj-$(CONFIG_IP_NF_MATCH_AH) += ipt_ah.o | 49 | obj-$(CONFIG_IP_NF_MATCH_AH) += ipt_ah.o |
50 | obj-$(CONFIG_IP_NF_MATCH_ECN) += ipt_ecn.o | 50 | obj-$(CONFIG_IP_NF_MATCH_ECN) += ipt_ecn.o |
51 | obj-$(CONFIG_IP_NF_MATCH_RECENT) += ipt_recent.o | ||
52 | obj-$(CONFIG_IP_NF_MATCH_TTL) += ipt_ttl.o | 51 | obj-$(CONFIG_IP_NF_MATCH_TTL) += ipt_ttl.o |
53 | 52 | ||
54 | # targets | 53 | # targets |
diff --git a/net/ipv4/netfilter/ipt_recent.c b/net/ipv4/netfilter/ipt_recent.c deleted file mode 100644 index 3974d7cae5c..00000000000 --- a/net/ipv4/netfilter/ipt_recent.c +++ /dev/null | |||
@@ -1,501 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2006 Patrick McHardy <kaber@trash.net> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | * | ||
8 | * This is a replacement of the old ipt_recent module, which carried the | ||
9 | * following copyright notice: | ||
10 | * | ||
11 | * Author: Stephen Frost <sfrost@snowman.net> | ||
12 | * Copyright 2002-2003, Stephen Frost, 2.5.x port by laforge@netfilter.org | ||
13 | */ | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/ip.h> | ||
16 | #include <linux/moduleparam.h> | ||
17 | #include <linux/proc_fs.h> | ||
18 | #include <linux/seq_file.h> | ||
19 | #include <linux/string.h> | ||
20 | #include <linux/ctype.h> | ||
21 | #include <linux/list.h> | ||
22 | #include <linux/random.h> | ||
23 | #include <linux/jhash.h> | ||
24 | #include <linux/bitops.h> | ||
25 | #include <linux/skbuff.h> | ||
26 | #include <linux/inet.h> | ||
27 | #include <net/net_namespace.h> | ||
28 | |||
29 | #include <linux/netfilter/x_tables.h> | ||
30 | #include <linux/netfilter_ipv4/ipt_recent.h> | ||
31 | |||
32 | MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>"); | ||
33 | MODULE_DESCRIPTION("Xtables: \"recently-seen\" host matching for IPv4"); | ||
34 | MODULE_LICENSE("GPL"); | ||
35 | |||
36 | static unsigned int ip_list_tot = 100; | ||
37 | static unsigned int ip_pkt_list_tot = 20; | ||
38 | static unsigned int ip_list_hash_size = 0; | ||
39 | static unsigned int ip_list_perms = 0644; | ||
40 | static unsigned int ip_list_uid = 0; | ||
41 | static unsigned int ip_list_gid = 0; | ||
42 | module_param(ip_list_tot, uint, 0400); | ||
43 | module_param(ip_pkt_list_tot, uint, 0400); | ||
44 | module_param(ip_list_hash_size, uint, 0400); | ||
45 | module_param(ip_list_perms, uint, 0400); | ||
46 | module_param(ip_list_uid, uint, 0400); | ||
47 | module_param(ip_list_gid, uint, 0400); | ||
48 | MODULE_PARM_DESC(ip_list_tot, "number of IPs to remember per list"); | ||
49 | MODULE_PARM_DESC(ip_pkt_list_tot, "number of packets per IP to remember (max. 255)"); | ||
50 | MODULE_PARM_DESC(ip_list_hash_size, "size of hash table used to look up IPs"); | ||
51 | MODULE_PARM_DESC(ip_list_perms, "permissions on /proc/net/ipt_recent/* files"); | ||
52 | MODULE_PARM_DESC(ip_list_uid,"owner of /proc/net/ipt_recent/* files"); | ||
53 | MODULE_PARM_DESC(ip_list_gid,"owning group of /proc/net/ipt_recent/* files"); | ||
54 | |||
55 | struct recent_entry { | ||
56 | struct list_head list; | ||
57 | struct list_head lru_list; | ||
58 | __be32 addr; | ||
59 | u_int8_t ttl; | ||
60 | u_int8_t index; | ||
61 | u_int16_t nstamps; | ||
62 | unsigned long stamps[0]; | ||
63 | }; | ||
64 | |||
65 | struct recent_table { | ||
66 | struct list_head list; | ||
67 | char name[IPT_RECENT_NAME_LEN]; | ||
68 | #ifdef CONFIG_PROC_FS | ||
69 | struct proc_dir_entry *proc; | ||
70 | #endif | ||
71 | unsigned int refcnt; | ||
72 | unsigned int entries; | ||
73 | struct list_head lru_list; | ||
74 | struct list_head iphash[0]; | ||
75 | }; | ||
76 | |||
77 | static LIST_HEAD(tables); | ||
78 | static DEFINE_SPINLOCK(recent_lock); | ||
79 | static DEFINE_MUTEX(recent_mutex); | ||
80 | |||
81 | #ifdef CONFIG_PROC_FS | ||
82 | static struct proc_dir_entry *proc_dir; | ||
83 | static const struct file_operations recent_fops; | ||
84 | #endif | ||
85 | |||
86 | static u_int32_t hash_rnd; | ||
87 | static int hash_rnd_initted; | ||
88 | |||
89 | static unsigned int recent_entry_hash(__be32 addr) | ||
90 | { | ||
91 | if (!hash_rnd_initted) { | ||
92 | get_random_bytes(&hash_rnd, 4); | ||
93 | hash_rnd_initted = 1; | ||
94 | } | ||
95 | return jhash_1word((__force u32)addr, hash_rnd) & (ip_list_hash_size - 1); | ||
96 | } | ||
97 | |||
98 | static struct recent_entry * | ||
99 | recent_entry_lookup(const struct recent_table *table, __be32 addr, u_int8_t ttl) | ||
100 | { | ||
101 | struct recent_entry *e; | ||
102 | unsigned int h; | ||
103 | |||
104 | h = recent_entry_hash(addr); | ||
105 | list_for_each_entry(e, &table->iphash[h], list) | ||
106 | if (e->addr == addr && (ttl == e->ttl || !ttl || !e->ttl)) | ||
107 | return e; | ||
108 | return NULL; | ||
109 | } | ||
110 | |||
111 | static void recent_entry_remove(struct recent_table *t, struct recent_entry *e) | ||
112 | { | ||
113 | list_del(&e->list); | ||
114 | list_del(&e->lru_list); | ||
115 | kfree(e); | ||
116 | t->entries--; | ||
117 | } | ||
118 | |||
119 | static struct recent_entry * | ||
120 | recent_entry_init(struct recent_table *t, __be32 addr, u_int8_t ttl) | ||
121 | { | ||
122 | struct recent_entry *e; | ||
123 | |||
124 | if (t->entries >= ip_list_tot) { | ||
125 | e = list_entry(t->lru_list.next, struct recent_entry, lru_list); | ||
126 | recent_entry_remove(t, e); | ||
127 | } | ||
128 | e = kmalloc(sizeof(*e) + sizeof(e->stamps[0]) * ip_pkt_list_tot, | ||
129 | GFP_ATOMIC); | ||
130 | if (e == NULL) | ||
131 | return NULL; | ||
132 | e->addr = addr; | ||
133 | e->ttl = ttl; | ||
134 | e->stamps[0] = jiffies; | ||
135 | e->nstamps = 1; | ||
136 | e->index = 1; | ||
137 | list_add_tail(&e->list, &t->iphash[recent_entry_hash(addr)]); | ||
138 | list_add_tail(&e->lru_list, &t->lru_list); | ||
139 | t->entries++; | ||
140 | return e; | ||
141 | } | ||
142 | |||
143 | static void recent_entry_update(struct recent_table *t, struct recent_entry *e) | ||
144 | { | ||
145 | e->stamps[e->index++] = jiffies; | ||
146 | if (e->index > e->nstamps) | ||
147 | e->nstamps = e->index; | ||
148 | e->index %= ip_pkt_list_tot; | ||
149 | list_move_tail(&e->lru_list, &t->lru_list); | ||
150 | } | ||
151 | |||
152 | static struct recent_table *recent_table_lookup(const char *name) | ||
153 | { | ||
154 | struct recent_table *t; | ||
155 | |||
156 | list_for_each_entry(t, &tables, list) | ||
157 | if (!strcmp(t->name, name)) | ||
158 | return t; | ||
159 | return NULL; | ||
160 | } | ||
161 | |||
162 | static void recent_table_flush(struct recent_table *t) | ||
163 | { | ||
164 | struct recent_entry *e, *next; | ||
165 | unsigned int i; | ||
166 | |||
167 | for (i = 0; i < ip_list_hash_size; i++) | ||
168 | list_for_each_entry_safe(e, next, &t->iphash[i], list) | ||
169 | recent_entry_remove(t, e); | ||
170 | } | ||
171 | |||
172 | static bool | ||
173 | recent_mt(const struct sk_buff *skb, const struct net_device *in, | ||
174 | const struct net_device *out, const struct xt_match *match, | ||
175 | const void *matchinfo, int offset, unsigned int protoff, | ||
176 | bool *hotdrop) | ||
177 | { | ||
178 | const struct ipt_recent_info *info = matchinfo; | ||
179 | struct recent_table *t; | ||
180 | struct recent_entry *e; | ||
181 | __be32 addr; | ||
182 | u_int8_t ttl; | ||
183 | bool ret = info->invert; | ||
184 | |||
185 | if (info->side == IPT_RECENT_DEST) | ||
186 | addr = ip_hdr(skb)->daddr; | ||
187 | else | ||
188 | addr = ip_hdr(skb)->saddr; | ||
189 | |||
190 | ttl = ip_hdr(skb)->ttl; | ||
191 | /* use TTL as seen before forwarding */ | ||
192 | if (out && !skb->sk) | ||
193 | ttl++; | ||
194 | |||
195 | spin_lock_bh(&recent_lock); | ||
196 | t = recent_table_lookup(info->name); | ||
197 | e = recent_entry_lookup(t, addr, | ||
198 | info->check_set & IPT_RECENT_TTL ? ttl : 0); | ||
199 | if (e == NULL) { | ||
200 | if (!(info->check_set & IPT_RECENT_SET)) | ||
201 | goto out; | ||
202 | e = recent_entry_init(t, addr, ttl); | ||
203 | if (e == NULL) | ||
204 | *hotdrop = true; | ||
205 | ret = !ret; | ||
206 | goto out; | ||
207 | } | ||
208 | |||
209 | if (info->check_set & IPT_RECENT_SET) | ||
210 | ret = !ret; | ||
211 | else if (info->check_set & IPT_RECENT_REMOVE) { | ||
212 | recent_entry_remove(t, e); | ||
213 | ret = !ret; | ||
214 | } else if (info->check_set & (IPT_RECENT_CHECK | IPT_RECENT_UPDATE)) { | ||
215 | unsigned long time = jiffies - info->seconds * HZ; | ||
216 | unsigned int i, hits = 0; | ||
217 | |||
218 | for (i = 0; i < e->nstamps; i++) { | ||
219 | if (info->seconds && time_after(time, e->stamps[i])) | ||
220 | continue; | ||
221 | if (++hits >= info->hit_count) { | ||
222 | ret = !ret; | ||
223 | break; | ||
224 | } | ||
225 | } | ||
226 | } | ||
227 | |||
228 | if (info->check_set & IPT_RECENT_SET || | ||
229 | (info->check_set & IPT_RECENT_UPDATE && ret)) { | ||
230 | recent_entry_update(t, e); | ||
231 | e->ttl = ttl; | ||
232 | } | ||
233 | out: | ||
234 | spin_unlock_bh(&recent_lock); | ||
235 | return ret; | ||
236 | } | ||
237 | |||
238 | static bool | ||
239 | recent_mt_check(const char *tablename, const void *ip, | ||
240 | const struct xt_match *match, void *matchinfo, | ||
241 | unsigned int hook_mask) | ||
242 | { | ||
243 | const struct ipt_recent_info *info = matchinfo; | ||
244 | struct recent_table *t; | ||
245 | unsigned i; | ||
246 | bool ret = false; | ||
247 | |||
248 | if (hweight8(info->check_set & | ||
249 | (IPT_RECENT_SET | IPT_RECENT_REMOVE | | ||
250 | IPT_RECENT_CHECK | IPT_RECENT_UPDATE)) != 1) | ||
251 | return false; | ||
252 | if ((info->check_set & (IPT_RECENT_SET | IPT_RECENT_REMOVE)) && | ||
253 | (info->seconds || info->hit_count)) | ||
254 | return false; | ||
255 | if (info->hit_count > ip_pkt_list_tot) | ||
256 | return false; | ||
257 | if (info->name[0] == '\0' || | ||
258 | strnlen(info->name, IPT_RECENT_NAME_LEN) == IPT_RECENT_NAME_LEN) | ||
259 | return false; | ||
260 | |||
261 | mutex_lock(&recent_mutex); | ||
262 | t = recent_table_lookup(info->name); | ||
263 | if (t != NULL) { | ||
264 | t->refcnt++; | ||
265 | ret = true; | ||
266 | goto out; | ||
267 | } | ||
268 | |||
269 | t = kzalloc(sizeof(*t) + sizeof(t->iphash[0]) * ip_list_hash_size, | ||
270 | GFP_KERNEL); | ||
271 | if (t == NULL) | ||
272 | goto out; | ||
273 | t->refcnt = 1; | ||
274 | strcpy(t->name, info->name); | ||
275 | INIT_LIST_HEAD(&t->lru_list); | ||
276 | for (i = 0; i < ip_list_hash_size; i++) | ||
277 | INIT_LIST_HEAD(&t->iphash[i]); | ||
278 | #ifdef CONFIG_PROC_FS | ||
279 | t->proc = proc_create(t->name, ip_list_perms, proc_dir, &recent_fops); | ||
280 | if (t->proc == NULL) { | ||
281 | kfree(t); | ||
282 | goto out; | ||
283 | } | ||
284 | t->proc->uid = ip_list_uid; | ||
285 | t->proc->gid = ip_list_gid; | ||
286 | t->proc->data = t; | ||
287 | #endif | ||
288 | spin_lock_bh(&recent_lock); | ||
289 | list_add_tail(&t->list, &tables); | ||
290 | spin_unlock_bh(&recent_lock); | ||
291 | ret = true; | ||
292 | out: | ||
293 | mutex_unlock(&recent_mutex); | ||
294 | return ret; | ||
295 | } | ||
296 | |||
297 | static void recent_mt_destroy(const struct xt_match *match, void *matchinfo) | ||
298 | { | ||
299 | const struct ipt_recent_info *info = matchinfo; | ||
300 | struct recent_table *t; | ||
301 | |||
302 | mutex_lock(&recent_mutex); | ||
303 | t = recent_table_lookup(info->name); | ||
304 | if (--t->refcnt == 0) { | ||
305 | spin_lock_bh(&recent_lock); | ||
306 | list_del(&t->list); | ||
307 | spin_unlock_bh(&recent_lock); | ||
308 | #ifdef CONFIG_PROC_FS | ||
309 | remove_proc_entry(t->name, proc_dir); | ||
310 | #endif | ||
311 | recent_table_flush(t); | ||
312 | kfree(t); | ||
313 | } | ||
314 | mutex_unlock(&recent_mutex); | ||
315 | } | ||
316 | |||
317 | #ifdef CONFIG_PROC_FS | ||
318 | struct recent_iter_state { | ||
319 | struct recent_table *table; | ||
320 | unsigned int bucket; | ||
321 | }; | ||
322 | |||
323 | static void *recent_seq_start(struct seq_file *seq, loff_t *pos) | ||
324 | __acquires(recent_lock) | ||
325 | { | ||
326 | struct recent_iter_state *st = seq->private; | ||
327 | const struct recent_table *t = st->table; | ||
328 | struct recent_entry *e; | ||
329 | loff_t p = *pos; | ||
330 | |||
331 | spin_lock_bh(&recent_lock); | ||
332 | |||
333 | for (st->bucket = 0; st->bucket < ip_list_hash_size; st->bucket++) | ||
334 | list_for_each_entry(e, &t->iphash[st->bucket], list) | ||
335 | if (p-- == 0) | ||
336 | return e; | ||
337 | return NULL; | ||
338 | } | ||
339 | |||
340 | static void *recent_seq_next(struct seq_file *seq, void *v, loff_t *pos) | ||
341 | { | ||
342 | struct recent_iter_state *st = seq->private; | ||
343 | const struct recent_table *t = st->table; | ||
344 | struct recent_entry *e = v; | ||
345 | struct list_head *head = e->list.next; | ||
346 | |||
347 | while (head == &t->iphash[st->bucket]) { | ||
348 | if (++st->bucket >= ip_list_hash_size) | ||
349 | return NULL; | ||
350 | head = t->iphash[st->bucket].next; | ||
351 | } | ||
352 | (*pos)++; | ||
353 | return list_entry(head, struct recent_entry, list); | ||
354 | } | ||
355 | |||
356 | static void recent_seq_stop(struct seq_file *s, void *v) | ||
357 | __releases(recent_lock) | ||
358 | { | ||
359 | spin_unlock_bh(&recent_lock); | ||
360 | } | ||
361 | |||
362 | static int recent_seq_show(struct seq_file *seq, void *v) | ||
363 | { | ||
364 | const struct recent_entry *e = v; | ||
365 | unsigned int i; | ||
366 | |||
367 | i = (e->index - 1) % ip_pkt_list_tot; | ||
368 | seq_printf(seq, "src=%u.%u.%u.%u ttl: %u last_seen: %lu oldest_pkt: %u", | ||
369 | NIPQUAD(e->addr), e->ttl, e->stamps[i], e->index); | ||
370 | for (i = 0; i < e->nstamps; i++) | ||
371 | seq_printf(seq, "%s %lu", i ? "," : "", e->stamps[i]); | ||
372 | seq_printf(seq, "\n"); | ||
373 | return 0; | ||
374 | } | ||
375 | |||
376 | static const struct seq_operations recent_seq_ops = { | ||
377 | .start = recent_seq_start, | ||
378 | .next = recent_seq_next, | ||
379 | .stop = recent_seq_stop, | ||
380 | .show = recent_seq_show, | ||
381 | }; | ||
382 | |||
383 | static int recent_seq_open(struct inode *inode, struct file *file) | ||
384 | { | ||
385 | struct proc_dir_entry *pde = PDE(inode); | ||
386 | struct recent_iter_state *st; | ||
387 | |||
388 | st = __seq_open_private(file, &recent_seq_ops, sizeof(*st)); | ||
389 | if (st == NULL) | ||
390 | return -ENOMEM; | ||
391 | |||
392 | st->table = pde->data; | ||
393 | return 0; | ||
394 | } | ||
395 | |||
396 | static ssize_t recent_proc_write(struct file *file, const char __user *input, | ||
397 | size_t size, loff_t *loff) | ||
398 | { | ||
399 | const struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode); | ||
400 | struct recent_table *t = pde->data; | ||
401 | struct recent_entry *e; | ||
402 | char buf[sizeof("+255.255.255.255")], *c = buf; | ||
403 | __be32 addr; | ||
404 | int add; | ||
405 | |||
406 | if (size > sizeof(buf)) | ||
407 | size = sizeof(buf); | ||
408 | if (copy_from_user(buf, input, size)) | ||
409 | return -EFAULT; | ||
410 | while (isspace(*c)) | ||
411 | c++; | ||
412 | |||
413 | if (size - (c - buf) < 5) | ||
414 | return c - buf; | ||
415 | if (!strncmp(c, "clear", 5)) { | ||
416 | c += 5; | ||
417 | spin_lock_bh(&recent_lock); | ||
418 | recent_table_flush(t); | ||
419 | spin_unlock_bh(&recent_lock); | ||
420 | return c - buf; | ||
421 | } | ||
422 | |||
423 | switch (*c) { | ||
424 | case '-': | ||
425 | add = 0; | ||
426 | c++; | ||
427 | break; | ||
428 | case '+': | ||
429 | c++; | ||
430 | default: | ||
431 | add = 1; | ||
432 | break; | ||
433 | } | ||
434 | addr = in_aton(c); | ||
435 | |||
436 | spin_lock_bh(&recent_lock); | ||
437 | e = recent_entry_lookup(t, addr, 0); | ||
438 | if (e == NULL) { | ||
439 | if (add) | ||
440 | recent_entry_init(t, addr, 0); | ||
441 | } else { | ||
442 | if (add) | ||
443 | recent_entry_update(t, e); | ||
444 | else | ||
445 | recent_entry_remove(t, e); | ||
446 | } | ||
447 | spin_unlock_bh(&recent_lock); | ||
448 | return size; | ||
449 | } | ||
450 | |||
451 | static const struct file_operations recent_fops = { | ||
452 | .open = recent_seq_open, | ||
453 | .read = seq_read, | ||
454 | .write = recent_proc_write, | ||
455 | .release = seq_release_private, | ||
456 | .owner = THIS_MODULE, | ||
457 | }; | ||
458 | #endif /* CONFIG_PROC_FS */ | ||
459 | |||
460 | static struct xt_match recent_mt_reg __read_mostly = { | ||
461 | .name = "recent", | ||
462 | .family = AF_INET, | ||
463 | .match = recent_mt, | ||
464 | .matchsize = sizeof(struct ipt_recent_info), | ||
465 | .checkentry = recent_mt_check, | ||
466 | .destroy = recent_mt_destroy, | ||
467 | .me = THIS_MODULE, | ||
468 | }; | ||
469 | |||
470 | static int __init recent_mt_init(void) | ||
471 | { | ||
472 | int err; | ||
473 | |||
474 | if (!ip_list_tot || !ip_pkt_list_tot || ip_pkt_list_tot > 255) | ||
475 | return -EINVAL; | ||
476 | ip_list_hash_size = 1 << fls(ip_list_tot); | ||
477 | |||
478 | err = xt_register_match(&recent_mt_reg); | ||
479 | #ifdef CONFIG_PROC_FS | ||
480 | if (err) | ||
481 | return err; | ||
482 | proc_dir = proc_mkdir("ipt_recent", init_net.proc_net); | ||
483 | if (proc_dir == NULL) { | ||
484 | xt_unregister_match(&recent_mt_reg); | ||
485 | err = -ENOMEM; | ||
486 | } | ||
487 | #endif | ||
488 | return err; | ||
489 | } | ||
490 | |||
491 | static void __exit recent_mt_exit(void) | ||
492 | { | ||
493 | BUG_ON(!list_empty(&tables)); | ||
494 | xt_unregister_match(&recent_mt_reg); | ||
495 | #ifdef CONFIG_PROC_FS | ||
496 | remove_proc_entry("ipt_recent", init_net.proc_net); | ||
497 | #endif | ||
498 | } | ||
499 | |||
500 | module_init(recent_mt_init); | ||
501 | module_exit(recent_mt_exit); | ||