/* * This is a module which is used for counting packets. */ #include #include #include #include #include #include #include #include struct in_device; #include #include //#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 depth) { // Empty data set if (!data) return; // Free for 8 bit network if (depth == 0) { free_page((unsigned long)data); data = NULL; return; } // Free for 16 bit network if (depth == 1) { 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) { free_page((unsigned long)mask_16->mask_24[b]); mask_16->mask_24[b] = NULL; } } free_page((unsigned long)data); data = NULL; return; } // Free for 24 bit network if (depth == 3) { 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]) { free_page((unsigned long)mask_16->mask_24[b]); mask_16->mask_24[b] = NULL; } } free_page((unsigned long)mask_16); mask_16 = NULL; } } free_page((unsigned long)data); data = NULL; return; } printk("ACCOUNT: ipt_account_data_free called with unknown depth: %d\n", depth); 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.%u.%u/%u.%u.%u.%u\n", name, NIPQUAD(ip), NIPQUAD(netmask)); // Look for existing table for (i = 0; i < ACCOUNT_MAX_TABLES; i++) { if (strcmp(ipt_account_tables[i].name, name) == 0) { DEBUGP("ACCOUNT: Found existing slot: %d - %u.%u.%u.%u/%u.%u.%u.%u\n", i, NIPQUAD(ipt_account_tables[i].ip), NIPQUAD(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.%u.%u/%u.%u.%u.%u\n", name, NIPQUAD(ipt_account_tables[i].ip), NIPQUAD(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, netsize=0; calc_mask = htonl(netmask); for (j = 31; j > 0; j--) { if (calc_mask&(1<= 24) ipt_account_tables[i].depth = 0; else if (netsize >= 16) ipt_account_tables[i].depth = 1; else if(netsize >= 8) ipt_account_tables[i].depth = 2; printk("ACCOUNT: calculated netsize: %u -> ipt_account_table depth %u\n", netsize, ipt_account_tables[i].depth); 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; } spin_lock_bh(&ipt_account_lock); 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"); spin_unlock_bh(&ipt_account_lock); return 0; } // Table nr caching so we don't have to do an extra string compare for every packet info->table_nr = table_nr; spin_unlock_bh(&ipt_account_lock); return 1; } void ipt_account_deleteentry(void *targinfo, unsigned int targinfosize) { unsigned int i; 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))); } spin_lock_bh(&ipt_account_lock); DEBUGP("ACCOUNT: ipt_account_deleteentry called for table: %s (#%d)\n", info->table_name, info->table_nr); info->table_nr = -1; // Set back to original state // Look for table for (i = 0; i < ACCOUNT_MAX_TABLES; i++) { if (strcmp(ipt_account_tables[i].name, info->table_name) == 0) { DEBUGP("ACCOUNT: Found table at slot: %d\n", i); ipt_account_tables[i].refcount--; DEBUGP("ACCOUNT: Refcount left: %d\n", ipt_account_tables[i].refcount); // Table not needed anymore? if (ipt_account_tables[i].refcount == 0) { DEBUGP("ACCOUNT: Destroying table at slot: %d\n", i); ipt_account_data_free(ipt_account_tables[i].data, ipt_account_tables[i].depth); memset(&ipt_account_tables[i], 0, sizeof(struct ipt_account_table)); } spin_unlock_bh(&ipt_account_lock); return; } } // Table not found printk("ACCOUNT: Table %s not found for destroy\n", info->table_name); spin_unlock_bh(&ipt_account_lock); } static struct ipt_target ipt_account_reg = { { NULL, NULL }, "ACCOUNT", ipt_account_target, ipt_account_checkentry, ipt_account_deleteentry, THIS_MODULE }; static int __init init(void) { if (!(ipt_account_tables = kmalloc(ACCOUNT_MAX_TABLES*sizeof(struct ipt_account_table), GFP_KERNEL))) { printk("ACCOUNT: Out of memory allocating account_tables structure"); return -EINVAL; } memset(ipt_account_tables, 0, ACCOUNT_MAX_TABLES*sizeof(struct ipt_account_table)); if (!(ipt_account_handles = kmalloc(ACCOUNT_MAX_HANDLES*sizeof(struct ipt_account_handle), GFP_KERNEL))) { printk("ACCOUNT: Out of memory allocating account_handles structure"); kfree (ipt_account_tables); ipt_account_tables = NULL; return -EINVAL; } memset(ipt_account_handles, 0, ACCOUNT_MAX_HANDLES*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");