1 include/linux/netfilter_ipv4/ipt_expire.h | 32 +
2 include/linux/netfilter_ipv6/ip6t_expire.h | 32 +
3 net/ipv4/netfilter/Kconfig | 11
4 net/ipv4/netfilter/Makefile | 1
5 net/ipv4/netfilter/ipt_expire.c | 563 ++++++++++++++++++++++++++++
6 net/ipv6/netfilter/Kconfig | 11
7 net/ipv6/netfilter/Makefile | 1
8 net/ipv6/netfilter/ip6t_expire.c | 566 +++++++++++++++++++++++++++++
9 8 files changed, 1217 insertions(+)
11 diff -Nur --exclude '*.orig' linux.org/include/linux/netfilter_ipv4/ipt_expire.h linux/include/linux/netfilter_ipv4/ipt_expire.h
12 --- linux.org/include/linux/netfilter_ipv4/ipt_expire.h 1970-01-01 01:00:00.000000000 +0100
13 +++ linux/include/linux/netfilter_ipv4/ipt_expire.h 2006-05-04 10:04:04.000000000 +0200
15 +/* This module matches until it expires, at which point the entire
18 + * This module is free software; you can redistribute it and/or modify
19 + * it under the terms of the GNU General Public License as published by
20 + * the Free Software Foundation; either version 2 of the License, or
21 + * (at your option) any later version.
23 + * This module is distributed in the hope that it will be useful,
24 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 + * GNU General Public License for more details.
28 + * You should have received a copy of the GNU General Public License
29 + * along with this module; if not, write to:
30 + * The Free Software Foundation, Inc.
31 + * 59 Temple Place, Suite 330
32 + * Boston, MA 02111-1307 USA
34 + * Copyright © 2005 Bryan Cardillo <dillo@seas.upenn.edu>
37 +#ifndef __IPT_EXPIRE_H
38 +#define __IPT_EXPIRE_H
40 +#include <linux/types.h>
42 +struct ipt_exp_info {
47 diff -Nur --exclude '*.orig' linux.org/include/linux/netfilter_ipv6/ip6t_expire.h linux/include/linux/netfilter_ipv6/ip6t_expire.h
48 --- linux.org/include/linux/netfilter_ipv6/ip6t_expire.h 1970-01-01 01:00:00.000000000 +0100
49 +++ linux/include/linux/netfilter_ipv6/ip6t_expire.h 2006-05-04 10:04:04.000000000 +0200
51 +/* This module matches until it expires, at which point the entire
54 + * This module is free software; you can redistribute it and/or modify
55 + * it under the terms of the GNU General Public License as published by
56 + * the Free Software Foundation; either version 2 of the License, or
57 + * (at your option) any later version.
59 + * This module is distributed in the hope that it will be useful,
60 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
61 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
62 + * GNU General Public License for more details.
64 + * You should have received a copy of the GNU General Public License
65 + * along with this module; if not, write to:
66 + * The Free Software Foundation, Inc.
67 + * 59 Temple Place, Suite 330
68 + * Boston, MA 02111-1307 USA
70 + * Copyright © 2005 Bryan Cardillo <dillo@seas.upenn.edu>
73 +#ifndef __IP6T_EXPIRE_H
74 +#define __IP6T_EXPIRE_H
76 +#include <linux/types.h>
78 +struct ip6t_exp_info {
83 diff -Nur --exclude '*.orig' linux.org/net/ipv4/netfilter/Kconfig linux/net/ipv4/netfilter/Kconfig
84 --- linux.org/net/ipv4/netfilter/Kconfig 2006-05-02 23:38:44.000000000 +0200
85 +++ linux/net/ipv4/netfilter/Kconfig 2006-05-04 10:04:04.000000000 +0200
87 Allows altering the ARP packet payload: source and destination
88 hardware and network addresses.
90 +config IP_NF_MATCH_EXPIRE
91 + tristate 'expiring match support'
92 + depends on IP_NF_IPTABLES
94 + This option adds an expiring match, which allows you to add
95 + rules to your iptables ruleset which will later be removed
98 + If you want to compile it as a module, say M here and read
99 + Documentation/modules.txt. If unsure, say `N'.
103 diff -Nur --exclude '*.orig' linux.org/net/ipv4/netfilter/Makefile linux/net/ipv4/netfilter/Makefile
104 --- linux.org/net/ipv4/netfilter/Makefile 2006-05-02 23:38:44.000000000 +0200
105 +++ linux/net/ipv4/netfilter/Makefile 2006-05-04 10:04:04.000000000 +0200
107 +obj-$(CONFIG_IP_NF_MATCH_EXPIRE) += ipt_expire.o
108 diff -Nur --exclude '*.orig' linux.org/net/ipv4/netfilter/ipt_expire.c linux/net/ipv4/netfilter/ipt_expire.c
109 --- linux.org/net/ipv4/netfilter/ipt_expire.c 1970-01-01 01:00:00.000000000 +0100
110 +++ linux/net/ipv4/netfilter/ipt_expire.c 2006-05-04 10:04:04.000000000 +0200
112 +/* This module matches until it expires, at which point the entire
115 + * This module is free software; you can redistribute it and/or modify
116 + * it under the terms of the GNU General Public License as published by
117 + * the Free Software Foundation; either version 2 of the License, or
118 + * (at your option) any later version.
120 + * This module is distributed in the hope that it will be useful,
121 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
122 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
123 + * GNU General Public License for more details.
125 + * You should have received a copy of the GNU General Public License
126 + * along with this module; if not, write to:
127 + * The Free Software Foundation, Inc.
128 + * 59 Temple Place, Suite 330
129 + * Boston, MA 02111-1307 USA
131 + * Copyright © 2005 Bryan Cardillo <dillo@seas.upenn.edu>
134 +#include <linux/config.h>
135 +#include <linux/kernel.h>
136 +#include <linux/module.h>
137 +#include <linux/workqueue.h>
138 +#include <linux/vmalloc.h>
139 +#include <linux/time.h>
140 +#include <linux/netfilter_ipv4/ip_tables.h>
141 +#include <linux/netfilter_ipv4/ipt_expire.h>
143 +#if CONFIG_NETFILTER_DEBUG
144 +#define dprintk(format, args...) \
145 + printk("ipt_expire[%s]: " format "\n", __FUNCTION__, ## args)
147 +#define dprintk(format, args...)
150 +MODULE_AUTHOR("Bryan Cardillo <dillo@seas.upenn.edu>");
151 +MODULE_DESCRIPTION("an iptables expiring match module");
152 +MODULE_LICENSE("GPL");
153 +MODULE_VERSION("1.1");
154 +static int __init ipt_exp_init(void);
155 +static void __exit ipt_exp_exit(void);
156 +module_init(ipt_exp_init);
157 +module_exit(ipt_exp_exit);
159 +static int ipt_exp_match(const struct sk_buff *,
160 + const struct net_device *, const struct net_device *,
161 + const void *, int, unsigned int, int *);
162 +static int ipt_exp_checkentry(const char *, const struct ipt_ip *,
163 + void *, unsigned int, unsigned int);
164 +static int ipt_exp_add_table(const char *);
165 +static void ipt_exp_remove_table(const char *);
166 +static void ipt_exp_schedule_expiration(time_t);
167 +static void ipt_exp_work_fn(void *);
168 +static int ipt_exp_get_info(const char *, struct ipt_getinfo *);
169 +static int ipt_exp_get_entries(struct ipt_getinfo *, struct ipt_get_entries *);
170 +static int ipt_exp_get_active(struct ipt_getinfo *,
171 + struct ipt_get_entries *, struct ipt_replace *);
172 +static int ipt_exp_copy_active(struct ipt_entry *, struct ipt_replace *);
173 +static int ipt_exp_is_expired(struct ipt_entry_match *);
174 +static int ipt_exp_replace_expired(struct ipt_replace *);
175 +static int ipt_exp_get_counters(struct ipt_get_entries *,
176 + struct ipt_replace *, struct ipt_counters_info *);
177 +static int ipt_exp_copy_counter(struct ipt_entry *, struct ipt_replace *,
178 + struct ipt_counters_info *, int *);
179 +static int ipt_exp_restore_counters(struct ipt_counters_info *);
182 + * struct for list of tables
184 +struct ipt_exp_table {
188 + char name[IPT_TABLE_MAXNAMELEN];
190 + * a list_head structure enabling list inclusion
192 + struct list_head list;
196 + * work_struct for scheduling the deletion of expired rules
198 +static DECLARE_WORK(ipt_exp_work, &ipt_exp_work_fn, NULL);
203 +static struct ipt_match ipt_expire_match = {
205 + .match = &ipt_exp_match,
206 + .checkentry = &ipt_exp_checkentry,
211 + * the list of tables contained expiring entries
213 +static spinlock_t ipt_exp_tables_lock = SPIN_LOCK_UNLOCKED;
214 +static LIST_HEAD(ipt_exp_tables);
217 + * initialize module and register iptables match
218 + * @see module_init()
219 + * @see ipt_register_match()
224 + dprintk("initializing");
225 + ipt_register_match(&ipt_expire_match);
230 + * cleanup module and unregister iptables match
231 + * @see module_exit()
232 + * @see ipt_unregister_match()
237 + unsigned long flags;
238 + struct ipt_exp_table *t, *tmp;
240 + dprintk("exiting");
242 + ipt_unregister_match(&ipt_expire_match);
243 + cancel_delayed_work(&ipt_exp_work);
245 + spin_lock_irqsave(&ipt_exp_tables_lock, flags);
246 + list_for_each_entry_safe(t, tmp, &ipt_exp_tables, list)
248 + spin_unlock_irqrestore(&ipt_exp_tables_lock, flags);
252 + * match if the expiration time has't passed
253 + * @param skb socket buffer
254 + * @param in inbound network device
255 + * @param out outbound network device
256 + * @param matchinfo match specific data
257 + * @param offset match offset (?)
258 + * @param hotdrop set to 1 to drop packet immediately when returning false
259 + * @return non-zero for active rules, zero otherwise
260 + * @see struct ipt_match
263 +ipt_exp_match(const struct sk_buff *skb,
264 + const struct net_device *in, const struct net_device *out,
265 + const void *matchinfo, int offset, unsigned int protoff, int *hotdrop)
267 + const struct ipt_exp_info *info = matchinfo;
269 + if (get_seconds() < info->expiration)
276 + * check a new iptables entry
277 + * @param tablename table name for new entry
278 + * @param ip ip info for new entry
279 + * @param matchinfo match specific data
280 + * @param matchsize size of matchinfo data
281 + * @param hookmask valid netfilter hooks (?)
282 + * @return non-zero for valid entries, zero otherwise
285 +ipt_exp_checkentry(const char *tablename, const struct ipt_ip *ip,
286 + void *matchinfo, unsigned int matchsize, unsigned int hookmask)
288 + struct ipt_exp_info *info = matchinfo;
290 + if (matchsize != IPT_ALIGN(sizeof(struct ipt_exp_info)))
293 + if (info->expiration <= get_seconds())
296 + if (ipt_exp_add_table(tablename))
299 + ipt_exp_schedule_expiration(info->expiration);
305 + * add a table to the set of tables to be searched for expired rules
306 + * @param tablename the name of the table
307 + * @return zero on success, non-zero on failure
310 +ipt_exp_add_table(const char *tablename)
312 + unsigned long flags;
313 + struct ipt_exp_table *t;
315 + spin_lock_irqsave(&ipt_exp_tables_lock, flags);
316 + list_for_each_entry(t, &ipt_exp_tables, list)
317 + if (strncmp(t->name, tablename, IPT_TABLE_MAXNAMELEN) == 0)
319 + spin_unlock_irqrestore(&ipt_exp_tables_lock, flags);
321 + if (&t->list == &ipt_exp_tables) {
322 + if (!(t = kmalloc(sizeof(struct ipt_exp_table), GFP_KERNEL))) {
323 + dprintk("error allocating memory");
326 + strlcpy(t->name, tablename, IPT_TABLE_MAXNAMELEN);
327 + spin_lock_irqsave(&ipt_exp_tables_lock, flags);
328 + list_add_tail(&t->list, &ipt_exp_tables);
329 + spin_unlock_irqrestore(&ipt_exp_tables_lock, flags);
335 + * remove a table from the set of tables to be searched for expired rules
336 + * @param tablename the name of the table to be removed
339 +ipt_exp_remove_table(const char *tablename)
341 + unsigned long flags;
342 + struct ipt_exp_table *t, *tmp;
344 + spin_lock_irqsave(&ipt_exp_tables_lock, flags);
345 + list_for_each_entry_safe(t, tmp, &ipt_exp_tables, list) {
346 + if (strncmp(t->name, tablename, IPT_TABLE_MAXNAMELEN) == 0) {
347 + list_del(&t->list);
351 + spin_unlock_irqrestore(&ipt_exp_tables_lock, flags);
355 + * schedule the next removal of expired rules
356 + * @param expiration the time to be scheduled
359 +ipt_exp_schedule_expiration(time_t expiration)
361 + unsigned long delay = (expiration - get_seconds() < 1) ? HZ :
362 + (expiration - get_seconds()) * HZ;
364 + schedule_delayed_work(&ipt_exp_work, delay);
368 + * delete expired iptables rules
370 + * @see schedule_delayed_work()
373 +ipt_exp_work_fn(void *__notused)
375 + struct ipt_exp_table *t;
378 + * FIXME what about locking here?
380 + list_for_each_entry(t, &ipt_exp_tables, list) {
382 + struct ipt_getinfo info;
383 + struct ipt_get_entries *entries = NULL;
384 + struct ipt_replace *replace = NULL;
385 + struct ipt_counters_info *counters = NULL;
387 + dprintk("expiring %s entries", t->name);
389 + /* get table info */
390 + if (ipt_exp_get_info(t->name, &info))
393 + /* allocate memory */
394 + sz = sizeof(struct ipt_get_entries) + info.size;
395 + if (!(entries = vmalloc(sz))) {
396 + dprintk("error allocating entry table");
399 + sz = sizeof(struct ipt_replace) + info.size;
400 + if (!(replace = vmalloc(sz))) {
401 + dprintk("error allocating replacement table");
402 + goto out_free_entries;
404 + memset(replace, 0, sz);
405 + sz = sizeof(struct ipt_counters) * info.num_entries;
406 + if (!(replace->counters = vmalloc(sz))) {
407 + dprintk("error allocating counters");
408 + goto out_free_entries_replace;
410 + memset(replace->counters, 0, sz);
411 + sz += sizeof(struct ipt_counters_info);
412 + if (!(counters = vmalloc(sz))) {
413 + dprintk("error allocating new counters");
414 + goto out_free_entries_replace_counters;
416 + memset(counters, 0, sz);
418 + /* get all entries, then copy active ones */
419 + if (ipt_exp_get_entries(&info, entries))
420 + goto out_free_entries_replace_counters_info;
421 + if (ipt_exp_get_active(&info, entries, replace))
422 + goto out_free_entries_replace_counters_info;
424 + /* replace table */
425 + if (replace->size < info.size) {
426 + if (ipt_exp_get_counters(entries, replace, counters))
427 + goto out_free_entries_replace_counters_info;
428 + if (ipt_exp_replace_expired(replace))
429 + goto out_free_entries_replace_counters_info;
430 + if (ipt_exp_restore_counters(counters))
431 + goto out_free_entries_replace_counters_info;
434 + dprintk("expired %s entries", t->name);
436 +out_free_entries_replace_counters_info:
438 +out_free_entries_replace_counters:
439 + vfree(replace->counters);
440 +out_free_entries_replace:
448 + * get info on an a table
449 + * @param name the name of the table
450 + * @param info the location to store the retrieved info
451 + * @return zero on success, non-zero otherwise
454 +ipt_exp_get_info(const char *name, struct ipt_getinfo *info)
457 + int sz = sizeof(struct ipt_getinfo);
459 + dprintk("getting entry info");
461 + strlcpy(info->name, name, IPT_TABLE_MAXNAMELEN);
462 + ret = nf_getsockopt(NULL, PF_INET, IPT_SO_GET_INFO, (char *)info, &sz);
467 + /* table is gone */
468 + ipt_exp_remove_table(name);
471 + dprintk("error getting iptables info");
479 + * get the entries for a table
480 + * @param info the location of info about the table
481 + * @param entries the location to allocate and store the retrieved entries
482 + * @return zero on success, non-zero otherwise
485 +ipt_exp_get_entries(struct ipt_getinfo *info, struct ipt_get_entries *entries)
488 + int sz = sizeof(struct ipt_get_entries) + info->size;
490 + dprintk("getting existing entries");
492 + strlcpy(entries->name, info->name, IPT_TABLE_MAXNAMELEN);
493 + entries->size = info->size;
494 + ret = nf_getsockopt(NULL, PF_INET,
495 + IPT_SO_GET_ENTRIES, (char *)entries, &sz);
497 + dprintk("error getting iptables entries");
503 + * iterate over a tables entries, copying entries which
504 + * are not expired to the replacement table
505 + * @param info the location of info about the table
506 + * @param entries the location of the table entries
507 + * @param replace the location to allocate and store the replacement entries
508 + * @return zero on success, non-zero otherwise
511 +ipt_exp_get_active(struct ipt_getinfo *info,
512 + struct ipt_get_entries *entries, struct ipt_replace *replace)
514 + dprintk("copying active entries");
517 + strlcpy(replace->name, info->name, IPT_TABLE_MAXNAMELEN);
518 + memcpy(replace->hook_entry, info->hook_entry, sizeof(info->hook_entry));
519 + memcpy(replace->underflow, info->underflow, sizeof(info->underflow));
520 + replace->valid_hooks = info->valid_hooks;
521 + replace->num_counters = info->num_entries;
523 + /* set size and entry count */
525 + replace->num_entries = 0;
527 + return IPT_ENTRY_ITERATE(entries->entrytable, entries->size,
528 + ipt_exp_copy_active, replace);
532 + * copy a table entry if it is not expired
533 + * @param entry the source entry
534 + * @param replace the replacement table
538 +ipt_exp_copy_active(struct ipt_entry *entry, struct ipt_replace *replace)
540 + if (!(IPT_MATCH_ITERATE(entry, ipt_exp_is_expired))) {
541 + struct ipt_entry *dest =
542 + (void *)replace->entries + replace->size;
543 + memcpy(dest, entry, entry->next_offset);
544 + replace->size += entry->next_offset;
545 + replace->num_entries++;
552 + * determine if an entry is expired
553 + * @param match the entry match to check for expiration
554 + * @return non-zero for expired entries, zero otherwise
557 +ipt_exp_is_expired(struct ipt_entry_match *match)
559 + if (strcmp(match->u.user.name, "expire") == 0) {
560 + struct ipt_exp_info *info = (struct ipt_exp_info *)match->data;
561 + if (info->expiration <= get_seconds())
569 + * @param replace the replacement table
570 + * @return zero on success, non-zero otherwise
573 +ipt_exp_replace_expired(struct ipt_replace *replace)
576 + int sz = sizeof(struct ipt_replace) + replace->size;
578 + dprintk("replacing table %s", replace->name);
580 + ret = nf_setsockopt(NULL, PF_INET,
581 + IPT_SO_SET_REPLACE, (char *)replace, sz);
583 + * FIXME remove this verbosity once tested?
589 + dprintk("EFAULT replacing iptables");
592 + dprintk("ENOPROTOOPT replacing iptables");
595 + dprintk("ENOMEM replacing iptables");
598 + dprintk("ENOENT replacing iptables");
601 + dprintk("ELOOP replacing iptables");
604 + dprintk("EINVAL replacing iptables");
607 + dprintk("unknown error (%d) replacing iptables", ret);
614 + * get counters for unexpired entries
615 + * @param entries the entries info
616 + * @param replace the replacement structure, containing the old counters
617 + * @param counters the new counter info
618 + * @return zero on success, non-zero on failure
621 +ipt_exp_get_counters(struct ipt_get_entries *entries,
622 + struct ipt_replace *replace,
623 + struct ipt_counters_info *counters)
626 + dprintk("copying active counters");
629 + strlcpy(counters->name, replace->name, IPT_TABLE_MAXNAMELEN);
630 + counters->num_counters = 0;
632 + return IPT_ENTRY_ITERATE(entries->entrytable, entries->size,
633 + ipt_exp_copy_counter, replace, counters, &index);
637 + * copy a rule counter if the rule is still active
638 + * @param entry the entry
639 + * @param replace the replacement structure containing the old counters
640 + * @param counter the new counter info
641 + * @param index the current entry index
645 +ipt_exp_copy_counter(struct ipt_entry *entry, struct ipt_replace *replace,
646 + struct ipt_counters_info *counters, int *index)
648 + if (!(IPT_MATCH_ITERATE(entry, ipt_exp_is_expired)))
649 + counters->counters[counters->num_counters++] =
650 + replace->counters[*index];
656 + * restore the counters for a table
657 + * @param counter the counters
658 + * @return zero on success, non-zero otherwise
661 +ipt_exp_restore_counters(struct ipt_counters_info *counters)
664 + int sz = sizeof(struct ipt_counters_info) +
665 + sizeof(struct ipt_counters) * counters->num_counters;
667 + dprintk("restoring counters for %s", counters->name);
669 + ret = nf_setsockopt(NULL, PF_INET,
670 + IPT_SO_SET_ADD_COUNTERS, (char *)counters, sz);
672 + dprintk("error restoring counters (%d)", ret);
675 diff -Nur --exclude '*.orig' linux.org/net/ipv6/netfilter/Kconfig linux/net/ipv6/netfilter/Kconfig
676 --- linux.org/net/ipv6/netfilter/Kconfig 2006-05-02 23:38:44.000000000 +0200
677 +++ linux/net/ipv6/netfilter/Kconfig 2006-05-04 10:04:04.000000000 +0200
679 If you want to compile it as a module, say M here and read
680 <file:Documentation/modules.txt>. If unsure, say `N'.
682 +config IP6_NF_MATCH_EXPIRE
683 + tristate 'expiring match support'
684 + depends on IP6_NF_IPTABLES
686 + This option adds an expiring match, which allows you to add
687 + rules to your iptables ruleset which will later be removed
690 + If you want to compile it as a module, say M here and read
691 + Documentation/modules.txt. If unsure, say `N'.
695 diff -Nur --exclude '*.orig' linux.org/net/ipv6/netfilter/Makefile linux/net/ipv6/netfilter/Makefile
696 --- linux.org/net/ipv6/netfilter/Makefile 2006-05-02 23:38:44.000000000 +0200
697 +++ linux/net/ipv6/netfilter/Makefile 2006-05-04 10:04:04.000000000 +0200
699 +obj-$(CONFIG_IP6_NF_MATCH_EXPIRE) += ip6t_expire.o
700 diff -Nur --exclude '*.orig' linux.org/net/ipv6/netfilter/ip6t_expire.c linux/net/ipv6/netfilter/ip6t_expire.c
701 --- linux.org/net/ipv6/netfilter/ip6t_expire.c 1970-01-01 01:00:00.000000000 +0100
702 +++ linux/net/ipv6/netfilter/ip6t_expire.c 2006-05-04 10:04:04.000000000 +0200
704 +/* This module matches until it expires, at which point the entire
707 + * This module is free software; you can redistribute it and/or modify
708 + * it under the terms of the GNU General Public License as published by
709 + * the Free Software Foundation; either version 2 of the License, or
710 + * (at your option) any later version.
712 + * This module is distributed in the hope that it will be useful,
713 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
714 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
715 + * GNU General Public License for more details.
717 + * You should have received a copy of the GNU General Public License
718 + * along with this module; if not, write to:
719 + * The Free Software Foundation, Inc.
720 + * 59 Temple Place, Suite 330
721 + * Boston, MA 02111-1307 USA
723 + * Copyright © 2005 Bryan Cardillo <dillo@seas.upenn.edu>
726 +#include <linux/config.h>
727 +#include <linux/kernel.h>
728 +#include <linux/module.h>
729 +#include <linux/workqueue.h>
730 +#include <linux/vmalloc.h>
731 +#include <linux/time.h>
732 +#include <linux/netfilter_ipv6/ip6_tables.h>
733 +#include <linux/netfilter_ipv6/ip6t_expire.h>
735 +#if CONFIG_NETFILTER_DEBUG
736 +#define dprintk(format, args...) \
737 + printk("ip6t_expire[%s]: " format "\n", __FUNCTION__, ## args)
739 +#define dprintk(format, args...)
742 +MODULE_AUTHOR("Bryan Cardillo <dillo@seas.upenn.edu>");
743 +MODULE_DESCRIPTION("an ip6tables expiring match module");
744 +MODULE_LICENSE("GPL");
745 +MODULE_VERSION("1.1");
746 +static int __init ip6t_exp_init(void);
747 +static void __exit ip6t_exp_exit(void);
748 +module_init(ip6t_exp_init);
749 +module_exit(ip6t_exp_exit);
751 +static int ip6t_exp_match(const struct sk_buff *,
752 + const struct net_device *, const struct net_device *,
753 + const void *, int, unsigned int, int *);
754 +static int ip6t_exp_checkentry(const char *, const struct ip6t_ip6 *,
755 + void *, unsigned int, unsigned int);
756 +static int ip6t_exp_add_table(const char *);
757 +static void ip6t_exp_remove_table(const char *);
758 +static void ip6t_exp_schedule_expiration(time_t);
759 +static void ip6t_exp_work_fn(void *);
760 +static int ip6t_exp_get_info(const char *, struct ip6t_getinfo *);
761 +static int ip6t_exp_get_entries(struct ip6t_getinfo *, struct ip6t_get_entries *);
762 +static int ip6t_exp_get_active(struct ip6t_getinfo *,
763 + struct ip6t_get_entries *, struct ip6t_replace *);
764 +static int ip6t_exp_copy_active(struct ip6t_entry *, struct ip6t_replace *);
765 +static int ip6t_exp_is_expired(struct ip6t_entry_match *);
766 +static int ip6t_exp_replace_expired(struct ip6t_replace *);
767 +static int ip6t_exp_get_counters(struct ip6t_get_entries *,
768 + struct ip6t_replace *, struct ip6t_counters_info *);
769 +static int ip6t_exp_copy_counter(struct ip6t_entry *, struct ip6t_replace *,
770 + struct ip6t_counters_info *, int *);
771 +static int ip6t_exp_restore_counters(struct ip6t_counters_info *);
774 + * struct for list of tables
776 +struct ip6t_exp_table {
780 + char name[IP6T_TABLE_MAXNAMELEN];
782 + * a list_head structure enabling list inclusion
784 + struct list_head list;
788 + * work_struct for scheduling the deletion of expired rules
790 +static DECLARE_WORK(ip6t_exp_work, &ip6t_exp_work_fn, NULL);
795 +static struct ip6t_match ip6t_expire_match = {
797 + .match = &ip6t_exp_match,
798 + .checkentry = &ip6t_exp_checkentry,
803 + * the list of tables contained expiring entries
805 +static spinlock_t ip6t_exp_tables_lock = SPIN_LOCK_UNLOCKED;
806 +static LIST_HEAD(ip6t_exp_tables);
809 + * initialize module and register ip6tables match
810 + * @see module_init()
811 + * @see ip6t_register_match()
816 + dprintk("initializing");
817 + ip6t_register_match(&ip6t_expire_match);
822 + * cleanup module and unregister ip6tables match
823 + * @see module_exit()
824 + * @see ip6t_unregister_match()
829 + unsigned long flags;
830 + struct ip6t_exp_table *t, *tmp;
832 + dprintk("exiting");
834 + ip6t_unregister_match(&ip6t_expire_match);
835 + cancel_delayed_work(&ip6t_exp_work);
837 + spin_lock_irqsave(&ip6t_exp_tables_lock, flags);
838 + list_for_each_entry_safe(t, tmp, &ip6t_exp_tables, list)
840 + spin_unlock_irqrestore(&ip6t_exp_tables_lock, flags);
844 + * match if the expiration time has't passed
845 + * @param skb socket buffer
846 + * @param in inbound network device
847 + * @param out outbound network device
848 + * @param matchinfo match specific data
849 + * @param offset match offset (?)
850 + * @param header (?)
852 + * @param hotdrop set to 1 to drop packet immediately when returning false
853 + * @return non-zero for active rules, zero otherwise
854 + * @see struct ip6t_match
857 +ip6t_exp_match(const struct sk_buff *skb,
858 + const struct net_device *in, const struct net_device *out,
859 + const void *matchinfo, int offset,
860 + unsigned int protoff, int *hotdrop)
862 + const struct ip6t_exp_info *info = matchinfo;
864 + if (get_seconds() < info->expiration)
871 + * check a new ip6tables entry
872 + * @param tablename table name for new entry
873 + * @param ip ip info for new entry
874 + * @param matchinfo match specific data
875 + * @param matchsize size of matchinfo data
876 + * @param hookmask valid netfilter hooks (?)
877 + * @return non-zero for valid entries, zero otherwise
880 +ip6t_exp_checkentry(const char *tablename, const struct ip6t_ip6 *ip,
881 + void *matchinfo, unsigned int matchsize, unsigned int hookmask)
883 + struct ip6t_exp_info *info = matchinfo;
885 + if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_exp_info)))
888 + if (info->expiration <= get_seconds())
891 + if (ip6t_exp_add_table(tablename))
894 + ip6t_exp_schedule_expiration(info->expiration);
900 + * add a table to the set of tables to be searched for expired rules
901 + * @param tablename the name of the table
902 + * @return zero on success, non-zero on failure
905 +ip6t_exp_add_table(const char *tablename)
907 + unsigned long flags;
908 + struct ip6t_exp_table *t;
910 + spin_lock_irqsave(&ip6t_exp_tables_lock, flags);
911 + list_for_each_entry(t, &ip6t_exp_tables, list)
912 + if (strncmp(t->name, tablename, IP6T_TABLE_MAXNAMELEN) == 0)
914 + spin_unlock_irqrestore(&ip6t_exp_tables_lock, flags);
916 + if (&t->list == &ip6t_exp_tables) {
917 + if (!(t = kmalloc(sizeof(struct ip6t_exp_table), GFP_KERNEL))) {
918 + dprintk("error allocating memory");
921 + strlcpy(t->name, tablename, IP6T_TABLE_MAXNAMELEN);
922 + spin_lock_irqsave(&ip6t_exp_tables_lock, flags);
923 + list_add_tail(&t->list, &ip6t_exp_tables);
924 + spin_unlock_irqrestore(&ip6t_exp_tables_lock, flags);
930 + * remove a table from the set of tables to be searched for expired rules
931 + * @param tablename the name of the table to be removed
934 +ip6t_exp_remove_table(const char *tablename)
936 + unsigned long flags;
937 + struct ip6t_exp_table *t, *tmp;
939 + spin_lock_irqsave(&ip6t_exp_tables_lock, flags);
940 + list_for_each_entry_safe(t, tmp, &ip6t_exp_tables, list) {
941 + if (strncmp(t->name, tablename, IP6T_TABLE_MAXNAMELEN) == 0) {
942 + list_del(&t->list);
946 + spin_unlock_irqrestore(&ip6t_exp_tables_lock, flags);
950 + * schedule the next removal of expired rules
951 + * @param expiration the time to be scheduled
954 +ip6t_exp_schedule_expiration(time_t expiration)
956 + unsigned long delay = (expiration - get_seconds() < 1) ? HZ :
957 + (expiration - get_seconds()) * HZ;
959 + schedule_delayed_work(&ip6t_exp_work, delay);
963 + * delete expired ip6tables rules
965 + * @see schedule_delayed_work()
968 +ip6t_exp_work_fn(void *__notused)
970 + struct ip6t_exp_table *t;
973 + * FIXME what about locking here?
975 + list_for_each_entry(t, &ip6t_exp_tables, list) {
977 + struct ip6t_getinfo info;
978 + struct ip6t_get_entries *entries = NULL;
979 + struct ip6t_replace *replace = NULL;
980 + struct ip6t_counters_info *counters = NULL;
982 + dprintk("expiring %s entries", t->name);
984 + /* get table info */
985 + if (ip6t_exp_get_info(t->name, &info))
988 + /* allocate memory */
989 + sz = sizeof(struct ip6t_get_entries) + info.size;
990 + if (!(entries = vmalloc(sz))) {
991 + dprintk("error allocating entry table");
994 + sz = sizeof(struct ip6t_replace) + info.size;
995 + if (!(replace = vmalloc(sz))) {
996 + dprintk("error allocating replacement table");
997 + goto out_free_entries;
999 + memset(replace, 0, sz);
1000 + sz = sizeof(struct ip6t_counters) * info.num_entries;
1001 + if (!(replace->counters = vmalloc(sz))) {
1002 + dprintk("error allocating counters");
1003 + goto out_free_entries_replace;
1005 + memset(replace->counters, 0, sz);
1006 + sz += sizeof(struct ip6t_counters_info);
1007 + if (!(counters = vmalloc(sz))) {
1008 + dprintk("error allocating new counters");
1009 + goto out_free_entries_replace_counters;
1011 + memset(counters, 0, sz);
1013 + /* get all entries, then copy active ones */
1014 + if (ip6t_exp_get_entries(&info, entries))
1015 + goto out_free_entries_replace_counters_info;
1016 + if (ip6t_exp_get_active(&info, entries, replace))
1017 + goto out_free_entries_replace_counters_info;
1019 + /* replace table */
1020 + if (replace->size < info.size) {
1021 + if (ip6t_exp_get_counters(entries, replace, counters))
1022 + goto out_free_entries_replace_counters_info;
1023 + if (ip6t_exp_replace_expired(replace))
1024 + goto out_free_entries_replace_counters_info;
1025 + if (ip6t_exp_restore_counters(counters))
1026 + goto out_free_entries_replace_counters_info;
1029 + dprintk("expired %s entries", t->name);
1031 +out_free_entries_replace_counters_info:
1033 +out_free_entries_replace_counters:
1034 + vfree(replace->counters);
1035 +out_free_entries_replace:
1043 + * get info on an a table
1044 + * @param name the name of the table
1045 + * @param info the location to store the retrieved info
1046 + * @return zero on success, non-zero otherwise
1049 +ip6t_exp_get_info(const char *name, struct ip6t_getinfo *info)
1052 + int sz = sizeof(struct ip6t_getinfo);
1054 + dprintk("getting entry info");
1056 + strlcpy(info->name, name, IP6T_TABLE_MAXNAMELEN);
1057 + ret = nf_getsockopt(NULL, PF_INET, IP6T_SO_GET_INFO, (char *)info, &sz);
1062 + /* table is gone */
1063 + ip6t_exp_remove_table(name);
1066 + dprintk("error getting ip6tables info");
1074 + * get the entries for a table
1075 + * @param info the location of info about the table
1076 + * @param entries the location to allocate and store the retrieved entries
1077 + * @return zero on success, non-zero otherwise
1080 +ip6t_exp_get_entries(struct ip6t_getinfo *info, struct ip6t_get_entries *entries)
1083 + int sz = sizeof(struct ip6t_get_entries) + info->size;
1085 + dprintk("getting existing entries");
1087 + strlcpy(entries->name, info->name, IP6T_TABLE_MAXNAMELEN);
1088 + entries->size = info->size;
1089 + ret = nf_getsockopt(NULL, PF_INET,
1090 + IP6T_SO_GET_ENTRIES, (char *)entries, &sz);
1092 + dprintk("error getting ip6tables entries");
1098 + * iterate over a tables entries, copying entries which
1099 + * are not expired to the replacement table
1100 + * @param info the location of info about the table
1101 + * @param entries the location of the table entries
1102 + * @param replace the location to allocate and store the replacement entries
1103 + * @return zero on success, non-zero otherwise
1106 +ip6t_exp_get_active(struct ip6t_getinfo *info,
1107 + struct ip6t_get_entries *entries, struct ip6t_replace *replace)
1109 + dprintk("copying active entries");
1112 + strlcpy(replace->name, info->name, IP6T_TABLE_MAXNAMELEN);
1113 + memcpy(replace->hook_entry, info->hook_entry, sizeof(info->hook_entry));
1114 + memcpy(replace->underflow, info->underflow, sizeof(info->underflow));
1115 + replace->valid_hooks = info->valid_hooks;
1116 + replace->num_counters = info->num_entries;
1118 + /* set size and entry count */
1119 + replace->size = 0;
1120 + replace->num_entries = 0;
1122 + return IP6T_ENTRY_ITERATE(entries->entrytable, entries->size,
1123 + ip6t_exp_copy_active, replace);
1127 + * copy a table entry if it is not expired
1128 + * @param entry the source entry
1129 + * @param replace the replacement table
1133 +ip6t_exp_copy_active(struct ip6t_entry *entry, struct ip6t_replace *replace)
1135 + if (!(IP6T_MATCH_ITERATE(entry, ip6t_exp_is_expired))) {
1136 + struct ip6t_entry *dest =
1137 + (void *)replace->entries + replace->size;
1138 + memcpy(dest, entry, entry->next_offset);
1139 + replace->size += entry->next_offset;
1140 + replace->num_entries++;
1147 + * determine if an entry is expired
1148 + * @param match the entry match to check for expiration
1149 + * @return non-zero for expired entries, zero otherwise
1152 +ip6t_exp_is_expired(struct ip6t_entry_match *match)
1154 + if (strcmp(match->u.user.name, "expire") == 0) {
1155 + struct ip6t_exp_info *info = (struct ip6t_exp_info *)match->data;
1156 + if (info->expiration <= get_seconds())
1164 + * @param replace the replacement table
1165 + * @return zero on success, non-zero otherwise
1168 +ip6t_exp_replace_expired(struct ip6t_replace *replace)
1171 + int sz = sizeof(struct ip6t_replace) + replace->size;
1173 + dprintk("replacing table %s", replace->name);
1175 + ret = nf_setsockopt(NULL, PF_INET,
1176 + IP6T_SO_SET_REPLACE, (char *)replace, sz);
1178 + * FIXME remove this verbosity once tested?
1184 + dprintk("EFAULT replacing ip6tables");
1186 + case -ENOPROTOOPT:
1187 + dprintk("ENOPROTOOPT replacing ip6tables");
1190 + dprintk("ENOMEM replacing ip6tables");
1193 + dprintk("ENOENT replacing ip6tables");
1196 + dprintk("ELOOP replacing ip6tables");
1199 + dprintk("EINVAL replacing ip6tables");
1202 + dprintk("unknown error (%d) replacing ip6tables", ret);
1209 + * get counters for unexpired entries
1210 + * @param entries the entries info
1211 + * @param replace the replacement structure, containing the old counters
1212 + * @param counters the new counter info
1213 + * @return zero on success, non-zero on failure
1216 +ip6t_exp_get_counters(struct ip6t_get_entries *entries,
1217 + struct ip6t_replace *replace,
1218 + struct ip6t_counters_info *counters)
1221 + dprintk("copying active counters");
1224 + strlcpy(counters->name, replace->name, IP6T_TABLE_MAXNAMELEN);
1225 + counters->num_counters = 0;
1227 + return IP6T_ENTRY_ITERATE(entries->entrytable, entries->size,
1228 + ip6t_exp_copy_counter, replace, counters, &index);
1232 + * copy a rule counter if the rule is still active
1233 + * @param entry the entry
1234 + * @param replace the replacement structure containing the old counters
1235 + * @param counter the new counter info
1236 + * @param index the current entry index
1240 +ip6t_exp_copy_counter(struct ip6t_entry *entry, struct ip6t_replace *replace,
1241 + struct ip6t_counters_info *counters, int *index)
1243 + if (!(IP6T_MATCH_ITERATE(entry, ip6t_exp_is_expired)))
1244 + counters->counters[counters->num_counters++] =
1245 + replace->counters[*index];
1251 + * restore the counters for a table
1252 + * @param counter the counters
1253 + * @return zero on success, non-zero otherwise
1256 +ip6t_exp_restore_counters(struct ip6t_counters_info *counters)
1259 + int sz = sizeof(struct ip6t_counters_info) +
1260 + sizeof(struct ip6t_counters) * counters->num_counters;
1262 + dprintk("restoring counters for %s", counters->name);
1264 + ret = nf_setsockopt(NULL, PF_INET,
1265 + IP6T_SO_SET_ADD_COUNTERS, (char *)counters, sz);
1267 + dprintk("error restoring counters (%d)", ret);