Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / net / ipv4 / netfilter / ipt_recent.c
index 08b786a..b847ee4 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/ctype.h>
 #include <linux/ip.h>
 #include <linux/vmalloc.h>
+#include <linux/moduleparam.h>
 
 #include <linux/netfilter_ipv4/ip_tables.h>
 #include <linux/netfilter_ipv4/ipt_recent.h>
 #define HASH_LOG 9
 
 /* Defaults, these can be overridden on the module command-line. */
-static int ip_list_tot = 100;
-static int ip_pkt_list_tot = 20;
-static int ip_list_hash_size = 0;
-static int ip_list_perms = 0644;
+static unsigned int ip_list_tot = 100;
+static unsigned int ip_pkt_list_tot = 20;
+static unsigned int ip_list_hash_size = 0;
+static unsigned int ip_list_perms = 0644;
 #ifdef DEBUG
 static int debug = 1;
 #endif
@@ -37,13 +38,13 @@ KERN_INFO RECENT_NAME " " RECENT_VER ": Stephen Frost <sfrost@snowman.net>.  htt
 MODULE_AUTHOR("Stephen Frost <sfrost@snowman.net>");
 MODULE_DESCRIPTION("IP tables recently seen matching module " RECENT_VER);
 MODULE_LICENSE("GPL");
-MODULE_PARM(ip_list_tot,"i");
-MODULE_PARM(ip_pkt_list_tot,"i");
-MODULE_PARM(ip_list_hash_size,"i");
-MODULE_PARM(ip_list_perms,"i");
+module_param(ip_list_tot, uint, 0400);
+module_param(ip_pkt_list_tot, uint, 0400);
+module_param(ip_list_hash_size, uint, 0400);
+module_param(ip_list_perms, uint, 0400);
 #ifdef DEBUG
-MODULE_PARM(debug,"i");
-MODULE_PARM_DESC(debug,"debugging level, defaults to 1");
+module_param(debug, bool, 0600);
+MODULE_PARM_DESC(debug,"enable debugging output");
 #endif
 MODULE_PARM_DESC(ip_list_tot,"number of IPs to remember per list");
 MODULE_PARM_DESC(ip_pkt_list_tot,"number of packets per IP to remember");
@@ -89,7 +90,7 @@ static struct recent_ip_tables *r_tables = NULL;
 /* We protect r_list with this spinlock so two processors are not modifying
  * the list at the same time. 
  */
-static spinlock_t recent_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(recent_lock);
 
 #ifdef CONFIG_PROC_FS
 /* Our /proc/net/ipt_recent entry */
@@ -101,12 +102,14 @@ static int
 match(const struct sk_buff *skb,
       const struct net_device *in,
       const struct net_device *out,
+      const struct xt_match *match,
       const void *matchinfo,
       int offset,
+      unsigned int protoff,
       int *hotdrop);
 
 /* Function to hash a given address into the hash table of table_size size */
-int hash_func(unsigned int addr, int table_size)
+static int hash_func(unsigned int addr, int table_size)
 {
        int result = 0;
        unsigned int value = addr;
@@ -222,7 +225,7 @@ static int ip_recent_ctrl(struct file *file, const char __user *input, unsigned
                        curr_table->table[count].last_seen = 0;
                        curr_table->table[count].addr = 0;
                        curr_table->table[count].ttl = 0;
-                       memset(curr_table->table[count].last_pkts,0,ip_pkt_list_tot*sizeof(u_int32_t));
+                       memset(curr_table->table[count].last_pkts,0,ip_pkt_list_tot*sizeof(unsigned long));
                        curr_table->table[count].oldest_pkt = 0;
                        curr_table->table[count].time_pos = 0;
                        curr_table->time_info[count].position = count;
@@ -316,7 +319,7 @@ static int ip_recent_ctrl(struct file *file, const char __user *input, unsigned
        skb->nh.iph->daddr = 0;
        /* Clear ttl since we have no way of knowing it */
        skb->nh.iph->ttl = 0;
-       match(skb,NULL,NULL,info,0,NULL);
+       match(skb,NULL,NULL,NULL,info,0,0,NULL);
 
        kfree(skb->nh.iph);
 out_free_skb:
@@ -354,8 +357,10 @@ static int
 match(const struct sk_buff *skb,
       const struct net_device *in,
       const struct net_device *out,
+      const struct xt_match *match,
       const void *matchinfo,
       int offset,
+      unsigned int protoff,
       int *hotdrop)
 {
        int pkt_count, hits_found, ans;
@@ -501,7 +506,7 @@ match(const struct sk_buff *skb,
                location = time_info[curr_table->time_pos].position;
                hash_table[r_list[location].hash_entry] = -1;
                hash_table[hash_result] = location;
-               memset(r_list[location].last_pkts,0,ip_pkt_list_tot*sizeof(u_int32_t));
+               memset(r_list[location].last_pkts,0,ip_pkt_list_tot*sizeof(unsigned long));
                r_list[location].time_pos = curr_table->time_pos;
                r_list[location].addr = addr;
                r_list[location].ttl = ttl;
@@ -531,6 +536,7 @@ match(const struct sk_buff *skb,
                        }
                        if(info->seconds && info->hit_count) {
                                for(pkt_count = 0, hits_found = 0; pkt_count < ip_pkt_list_tot; pkt_count++) {
+                                       if(r_list[location].last_pkts[pkt_count] == 0) break;
                                        if(time_before_eq(now,r_list[location].last_pkts[pkt_count]+info->seconds*HZ)) hits_found++;
                                }
                                if(hits_found >= info->hit_count) ans = !info->invert; else ans = info->invert;
@@ -630,7 +636,7 @@ match(const struct sk_buff *skb,
                        r_list[location].last_seen = 0;
                        r_list[location].addr = 0;
                        r_list[location].ttl = 0;
-                       memset(r_list[location].last_pkts,0,ip_pkt_list_tot*sizeof(u_int32_t));
+                       memset(r_list[location].last_pkts,0,ip_pkt_list_tot*sizeof(unsigned long));
                        r_list[location].oldest_pkt = 0;
                        ans = !info->invert;
                }
@@ -652,7 +658,8 @@ match(const struct sk_buff *skb,
  */
 static int
 checkentry(const char *tablename,
-           const struct ipt_ip *ip,
+           const void *ip,
+          const struct xt_match *match,
            void *matchinfo,
            unsigned int matchsize,
            unsigned int hook_mask)
@@ -666,8 +673,6 @@ checkentry(const char *tablename,
        if(debug) printk(KERN_INFO RECENT_NAME ": checkentry() entered.\n");
 #endif
 
-       if (matchsize != IPT_ALIGN(sizeof(struct ipt_recent_info))) return 0;
-
        /* seconds and hit_count only valid for CHECK/UPDATE */
        if(info->check_set & IPT_RECENT_SET) { flag++; if(info->seconds || info->hit_count) return 0; }
        if(info->check_set & IPT_RECENT_REMOVE) { flag++; if(info->seconds || info->hit_count) return 0; }
@@ -712,9 +717,9 @@ checkentry(const char *tablename,
 #endif
 
        curr_table = vmalloc(sizeof(struct recent_ip_tables));
-       if(curr_table == NULL) return -ENOMEM;
+       if(curr_table == NULL) return 0;
 
-       curr_table->list_lock = SPIN_LOCK_UNLOCKED;
+       spin_lock_init(&curr_table->list_lock);
        curr_table->next = NULL;
        curr_table->count = 1;
        curr_table->time_pos = 0;
@@ -729,14 +734,14 @@ checkentry(const char *tablename,
 #endif
 
        curr_table->table = vmalloc(sizeof(struct recent_ip_list)*ip_list_tot);
-       if(curr_table->table == NULL) { vfree(curr_table); return -ENOMEM; }
+       if(curr_table->table == NULL) { vfree(curr_table); return 0; }
        memset(curr_table->table,0,sizeof(struct recent_ip_list)*ip_list_tot);
 #ifdef DEBUG
        if(debug) printk(KERN_INFO RECENT_NAME ": checkentry: Allocating %d for pkt_list.\n",
-                       sizeof(u_int32_t)*ip_pkt_list_tot*ip_list_tot);
+                       sizeof(unsigned long)*ip_pkt_list_tot*ip_list_tot);
 #endif
 
-       hold = vmalloc(sizeof(u_int32_t)*ip_pkt_list_tot*ip_list_tot);
+       hold = vmalloc(sizeof(unsigned long)*ip_pkt_list_tot*ip_list_tot);
 #ifdef DEBUG
        if(debug) printk(KERN_INFO RECENT_NAME ": checkentry: After pkt_list allocation.\n");
 #endif
@@ -744,7 +749,7 @@ checkentry(const char *tablename,
                printk(KERN_INFO RECENT_NAME ": checkentry: unable to allocate for pkt_list.\n");
                vfree(curr_table->table); 
                vfree(curr_table);
-               return -ENOMEM;
+               return 0;
        }
        for(c = 0; c < ip_list_tot; c++) {
                curr_table->table[c].last_pkts = hold + c*ip_pkt_list_tot;
@@ -762,7 +767,7 @@ checkentry(const char *tablename,
                vfree(hold);
                vfree(curr_table->table); 
                vfree(curr_table);
-               return -ENOMEM;
+               return 0;
        }
 
        for(c = 0; c < ip_list_hash_size; c++) {
@@ -782,7 +787,7 @@ checkentry(const char *tablename,
                vfree(hold);
                vfree(curr_table->table); 
                vfree(curr_table);
-               return -ENOMEM;
+               return 0;
        }
        for(c = 0; c < ip_list_tot; c++) {
                curr_table->time_info[c].position = c;
@@ -816,6 +821,7 @@ checkentry(const char *tablename,
        /* Create our proc 'status' entry. */
        curr_table->status_proc = create_proc_entry(curr_table->name, ip_list_perms, proc_net_ipt_recent);
        if (!curr_table->status_proc) {
+               vfree(hold);
                printk(KERN_INFO RECENT_NAME ": checkentry: unable to allocate for /proc entry.\n");
                /* Destroy the created table */
                spin_lock_bh(&recent_lock);
@@ -826,7 +832,7 @@ checkentry(const char *tablename,
                        if(debug) printk(KERN_INFO RECENT_NAME ": checkentry() create_proc failed, no tables.\n");
 #endif
                        spin_unlock_bh(&recent_lock);
-                       return -ENOMEM;
+                       return 0;
                }
                while( strncmp(info->name,curr_table->name,IPT_RECENT_NAME_LEN) && (last_table = curr_table) && (curr_table = curr_table->next) );
                if(!curr_table) {
@@ -834,16 +840,15 @@ checkentry(const char *tablename,
                        if(debug) printk(KERN_INFO RECENT_NAME ": checkentry() create_proc failed, table already destroyed.\n");
 #endif
                        spin_unlock_bh(&recent_lock);
-                       return -ENOMEM;
+                       return 0;
                }
                if(last_table) last_table->next = curr_table->next; else r_tables = curr_table->next;
                spin_unlock_bh(&recent_lock);
                vfree(curr_table->time_info);
                vfree(curr_table->hash_table);
-               vfree(hold);
                vfree(curr_table->table);
                vfree(curr_table);
-               return -ENOMEM;
+               return 0;
        }
        
        curr_table->status_proc->owner = THIS_MODULE;
@@ -867,7 +872,7 @@ checkentry(const char *tablename,
  * up its memory.
  */
 static void
-destroy(void *matchinfo, unsigned int matchsize)
+destroy(const struct xt_match *match, void *matchinfo, unsigned int matchsize)
 {
        const struct ipt_recent_info *info = matchinfo;
        struct recent_ip_tables *curr_table, *last_table;
@@ -947,18 +952,19 @@ destroy(void *matchinfo, unsigned int matchsize)
 /* This is the structure we pass to ipt_register to register our
  * module with iptables.
  */
-static struct ipt_match recent_match = { 
-  .name = "recent", 
-  .match = &match, 
-  .checkentry = &checkentry, 
-  .destroy = &destroy, 
-  .me = THIS_MODULE
+static struct ipt_match recent_match = {
+       .name           = "recent",
+       .match          = match,
+       .matchsize      = sizeof(struct ipt_recent_info),
+       .checkentry     = checkentry,
+       .destroy        = destroy,
+       .me             = THIS_MODULE
 };
 
 /* Kernel module initialization. */
-static int __init init(void)
+static int __init ipt_recent_init(void)
 {
-       int count;
+       int err, count;
 
        printk(version);
 #ifdef CONFIG_PROC_FS
@@ -982,11 +988,14 @@ static int __init init(void)
        if(debug) printk(KERN_INFO RECENT_NAME ": ip_list_hash_size: %d\n",ip_list_hash_size);
 #endif
 
-       return ipt_register_match(&recent_match);
+       err = ipt_register_match(&recent_match);
+       if (err)
+               remove_proc_entry("ipt_recent", proc_net);
+       return err;
 }
 
 /* Kernel module destruction. */
-static void __exit fini(void)
+static void __exit ipt_recent_fini(void)
 {
        ipt_unregister_match(&recent_match);
 
@@ -994,5 +1003,5 @@ static void __exit fini(void)
 }
 
 /* Register our module with the kernel. */
-module_init(init);
-module_exit(fini);
+module_init(ipt_recent_init);
+module_exit(ipt_recent_fini);