iptables: (tomj) small header, added ipt_account.c here until we have patch-o-matic
authorThomas Jarosch <thomas.jarosch@intra2net.com>
Thu, 8 Apr 2004 15:02:30 +0000 (15:02 +0000)
committerThomas Jarosch <thomas.jarosch@intra2net.com>
Thu, 8 Apr 2004 15:02:30 +0000 (15:02 +0000)
linux/include/linux/netfilter_ipv4/ipt_ACCOUNT.h
linux/net/ipv4/netfilter/ipt_ACCOUNT.c [new file with mode: 0644]

index 9718f4b..dc0ef91 100644 (file)
@@ -17,8 +17,9 @@ struct ipt_account_info {
 struct ipt_account_table
 {
     char name[ACCOUNT_TABLE_NAME_LEN];        /* name of the table */
-    unsigned int ip;                          /* base IP of network (-a option) */
-    unsigned char netmask;                    /* netmask of the network (-a option) */
+    unsigned int ip;                          /* base IP of network */
+    unsigned int netmask;                     /* netmask of the network */
+    unsigned char netsize;                    /* Number of bits used in this netmask */
     unsigned int refcount;                    /* refcount of this table. if zero, destroy it */
     unsigned int itemcount;                   /* number of IPs in this table */
     void *data;                               /* pointer to the actual data, depending on netmask */
diff --git a/linux/net/ipv4/netfilter/ipt_ACCOUNT.c b/linux/net/ipv4/netfilter/ipt_ACCOUNT.c
new file mode 100644 (file)
index 0000000..152c564
--- /dev/null
@@ -0,0 +1,240 @@
+/*
+ * This is a module which is used for counting packets.
+ */
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/ip.h>
+#include <linux/spinlock.h>
+#include <net/icmp.h>
+#include <net/udp.h>
+#include <net/tcp.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+
+struct in_device;
+#include <net/route.h>
+#include <linux/netfilter_ipv4/ipt_ACCOUNT.h>
+
+//#if 0
+#define DEBUGP printk
+//#else
+//#define DEBUGP(format, args...)
+//#endif
+
+struct ipt_account_table *ipt_account_tables = NULL;
+struct ipt_account_handle *ipt_account_handles = NULL;
+
+static spinlock_t ipt_account_lock = SPIN_LOCK_UNLOCKED;
+
+static unsigned int
+ipt_account_target(struct sk_buff **pskb,
+    unsigned int hooknum,
+    const struct net_device *in,
+    const struct net_device *out,
+    const void *targinfo,
+    void *userinfo)
+{
+    spin_lock_bh(&ipt_account_lock);
+    spin_unlock_bh(&ipt_account_lock);
+
+    return IPT_CONTINUE;
+}
+
+/* Recursive free of all data structures */
+void ipt_account_data_free(void *data, unsigned char netsize)
+{
+    // Empty data set
+    if (!data)
+        return;
+        
+    // Free for 8 bit network. Special: 0.0.0.0/0
+    if (netsize >= 24 || netsize == 0)
+    {
+        kfree(data);
+        data = NULL;
+        return;
+    }
+    
+    // Free for 16 bit network
+    if (netsize >= 16)
+    {
+        struct ipt_account_mask_16 *mask_16 = (struct ipt_account_mask_16 *)data;
+        unsigned char b;
+        for (b=0; b < 255; b++)
+        {
+            if (mask_16->mask_24[b] != 0)
+            {
+                kfree(mask_16->mask_24[b]);
+                mask_16->mask_24[b] = NULL;
+            }
+        }
+        kfree(data);
+        data = NULL;
+        return;
+    } 
+   
+    // Free for 24 bit network
+    if (netsize >= 8)
+    {
+        unsigned char a, b;
+        for (a=0; a < 255; a++)
+        {
+            if (((struct ipt_account_mask_8 *)data)->mask_16[a])
+            {
+                struct ipt_account_mask_16 *mask_16 = (struct ipt_account_mask_16*)((struct ipt_account_mask_8 *)data)->mask_16[a];
+                for (b=0; b < 255; b++)
+                {
+                    if (mask_16->mask_24[b]) {
+                        kfree(mask_16->mask_24[b]);
+                        mask_16->mask_24[b] = NULL;
+                    }
+                }
+                kfree(mask_16);
+                mask_16 = NULL;
+            }
+        }
+        kfree(data);
+        data = NULL;
+        return;
+    }
+    
+    printk("ACCOUNT: ipt_account_data_free called with broken netsize: %d\n", netsize);
+    return;
+}
+
+/* Look for existing table / insert new one. Return internal ID or -1 on error */
+int ipt_account_table_insert(char *name, unsigned int ip, unsigned int netmask)
+{
+    unsigned int i;
+
+    DEBUGP("ACCOUNT: ipt_account_table_insert: %s, %u/%u\n", name, ip, netmask);
+
+    // Look for existing table
+    for (i = 0; i < ACCOUNT_MAX_TABLES; i++)
+    {
+        if (strcmp(ipt_account_tables[i].name, name) == 0)
+        {
+            DEBUGP("ACCOUT: Found existing slot: %d - %u/%u\n", i, ipt_account_tables[i].ip, ipt_account_tables[i].netmask);
+            
+            if (ipt_account_tables[i].ip != ip || ipt_account_tables[i].netmask != netmask)
+            {
+                printk("ACCOUNT: Table %s found, but IP/netmask mismatch. IP/netmask found: %u/%u\n",
+                        name, ipt_account_tables[i].ip, ipt_account_tables[i].netmask);
+                return -1;
+            }
+
+            ipt_account_tables[i].refcount++;
+            DEBUGP("ACCOUNT: Refcount: %d\n", ipt_account_tables[i].refcount);
+            return i;
+        }
+    }
+
+    // Insert new table
+    for (i = 0; i < ACCOUNT_MAX_TABLES; i++)
+    {
+        // Found free slot
+        if (ipt_account_tables[i].name[0] == 0)
+        {
+            DEBUGP("ACCOUNT: Found free slot: %d\n", i);
+        
+            strncpy (ipt_account_tables[i].name, name, ACCOUNT_TABLE_NAME_LEN-1);
+            
+            ipt_account_tables[i].ip = ip;
+            ipt_account_tables[i].netmask = netmask;
+            
+            // calculate netsize
+            unsigned int j, calc_mask;
+            calc_mask = htonl(netmask);
+            for (j = 31; j > 0; j--)
+            {
+                if (calc_mask&(1<<j))
+                    ipt_account_tables[i].netsize++;
+                else
+                    break;
+            }
+            printk("ACCOUNT: calculated netsize: %u\n", ipt_account_tables[i].netsize);
+                        
+            ipt_account_tables[i].refcount++;
+            if (!(ipt_account_tables[i].data = (void *)get_zeroed_page(GFP_KERNEL)))
+            {
+                printk("ACCOUNT: Out of memory for data of table: %s\n", name);
+                memset(&ipt_account_tables[i], 0, sizeof(struct ipt_account_table));
+                return -1;
+            }
+            return i;
+        }
+    }
+        
+    // No free slot found
+    printk("ACCOUNT: No free table slot found (max: %d). Please increase ACCOUNT_MAX_TABLES.\n", ACCOUNT_MAX_TABLES);
+    return -1;
+}
+
+static int ipt_account_checkentry(const char *tablename,
+    const struct ipt_entry *e,
+    void *targinfo,
+    unsigned int targinfosize,
+    unsigned int hook_mask)
+{
+    struct ipt_account_info *info = targinfo;
+    
+    if (targinfosize != IPT_ALIGN(sizeof(struct ipt_account_info))) {
+        DEBUGP("ACCOUNT: targinfosize %u != %u\n",
+                targinfosize, IPT_ALIGN(sizeof(struct ipt_account_info)));
+        return 0;
+    }
+
+    int table_nr = ipt_account_table_insert(info->table_name, info->net_ip, info->net_mask);
+    if (table_nr == -1)
+    {
+        printk("ACCOUNT: Table insert problem. Aborting\n");
+        return 0;
+    }
+
+    // Table nr caching so we don't have to do an extra string compare for every packet
+    info->table_nr = table_nr;
+    
+    return 1;
+}
+
+static struct ipt_target ipt_account_reg
+= { { NULL, NULL }, "ACCOUNT", ipt_account_target, ipt_account_checkentry, NULL, 
+    THIS_MODULE };
+
+static int __init init(void)
+{
+    if (!(ipt_account_tables = kmalloc(ACCOUNT_MAX_TABLES, sizeof(struct ipt_account_table))))
+    {
+            printk("ACCOUNT: Out of memory allocating account_tables structure");
+            return -EINVAL;
+    }
+    memset(ipt_account_tables, 0, sizeof(struct ipt_account_table));
+                            
+    if (!(ipt_account_handles = kmalloc(ACCOUNT_MAX_HANDLES, sizeof(struct ipt_account_handle))))
+    {
+            printk("ACCOUNT: Out of memory allocating account_handles structure");
+            kfree (ipt_account_tables);
+            ipt_account_tables = NULL;
+            return -EINVAL;
+    }
+    memset(ipt_account_handles, 0, sizeof(struct ipt_account_handle));
+    
+    if (ipt_register_target(&ipt_account_reg))
+            return -EINVAL;
+
+    return 0;
+}
+
+static void __exit fini(void)
+{
+    ipt_unregister_target(&ipt_account_reg);
+
+    kfree(ipt_account_tables);
+    ipt_account_tables = NULL;
+        
+    kfree(ipt_account_handles);
+    ipt_account_handles = NULL;
+}
+
+module_init(init);
+module_exit(fini);
+MODULE_LICENSE("GPL");