iptables: (tomj) fixed badly broken memory handling, basic stuff now working
[ipt_ACCOUNT] / linux / net / ipv4 / netfilter / ipt_ACCOUNT.c
CommitLineData
70288420
TJ
1/*
2 * This is a module which is used for counting packets.
3 */
4#include <linux/module.h>
5#include <linux/skbuff.h>
6#include <linux/ip.h>
7#include <linux/spinlock.h>
8#include <net/icmp.h>
9#include <net/udp.h>
10#include <net/tcp.h>
11#include <linux/netfilter_ipv4/ip_tables.h>
12
13struct in_device;
14#include <net/route.h>
15#include <linux/netfilter_ipv4/ipt_ACCOUNT.h>
16
17//#if 0
18#define DEBUGP printk
19//#else
20//#define DEBUGP(format, args...)
21//#endif
22
23struct ipt_account_table *ipt_account_tables = NULL;
24struct ipt_account_handle *ipt_account_handles = NULL;
25
26static spinlock_t ipt_account_lock = SPIN_LOCK_UNLOCKED;
27
28static unsigned int
29ipt_account_target(struct sk_buff **pskb,
30 unsigned int hooknum,
31 const struct net_device *in,
32 const struct net_device *out,
33 const void *targinfo,
34 void *userinfo)
35{
36 spin_lock_bh(&ipt_account_lock);
37 spin_unlock_bh(&ipt_account_lock);
38
39 return IPT_CONTINUE;
40}
41
42/* Recursive free of all data structures */
850cece6 43void ipt_account_data_free(void *data, unsigned char depth)
70288420
TJ
44{
45 // Empty data set
46 if (!data)
47 return;
48
850cece6
TJ
49 // Free for 8 bit network
50 if (depth == 0)
70288420 51 {
850cece6 52 free_page((unsigned long)data);
70288420
TJ
53 data = NULL;
54 return;
55 }
56
57 // Free for 16 bit network
850cece6 58 if (depth == 1)
70288420
TJ
59 {
60 struct ipt_account_mask_16 *mask_16 = (struct ipt_account_mask_16 *)data;
61 unsigned char b;
62 for (b=0; b < 255; b++)
63 {
64 if (mask_16->mask_24[b] != 0)
65 {
850cece6 66 free_page((unsigned long)mask_16->mask_24[b]);
70288420
TJ
67 mask_16->mask_24[b] = NULL;
68 }
69 }
850cece6 70 free_page((unsigned long)data);
70288420
TJ
71 data = NULL;
72 return;
73 }
74
75 // Free for 24 bit network
850cece6 76 if (depth == 3)
70288420
TJ
77 {
78 unsigned char a, b;
79 for (a=0; a < 255; a++)
80 {
81 if (((struct ipt_account_mask_8 *)data)->mask_16[a])
82 {
83 struct ipt_account_mask_16 *mask_16 = (struct ipt_account_mask_16*)((struct ipt_account_mask_8 *)data)->mask_16[a];
84 for (b=0; b < 255; b++)
85 {
86 if (mask_16->mask_24[b]) {
850cece6 87 free_page((unsigned long)mask_16->mask_24[b]);
70288420
TJ
88 mask_16->mask_24[b] = NULL;
89 }
90 }
850cece6 91 free_page((unsigned long)mask_16);
70288420
TJ
92 mask_16 = NULL;
93 }
94 }
850cece6 95 free_page((unsigned long)data);
70288420
TJ
96 data = NULL;
97 return;
98 }
99
850cece6 100 printk("ACCOUNT: ipt_account_data_free called with unknown depth: %d\n", depth);
70288420
TJ
101 return;
102}
103
104/* Look for existing table / insert new one. Return internal ID or -1 on error */
105int ipt_account_table_insert(char *name, unsigned int ip, unsigned int netmask)
106{
107 unsigned int i;
108
850cece6 109 DEBUGP("ACCOUNT: ipt_account_table_insert: %s, %u.%u.%u.%u/%u.%u.%u.%u\n", name, NIPQUAD(ip), NIPQUAD(netmask));
70288420
TJ
110
111 // Look for existing table
112 for (i = 0; i < ACCOUNT_MAX_TABLES; i++)
113 {
114 if (strcmp(ipt_account_tables[i].name, name) == 0)
115 {
850cece6
TJ
116 DEBUGP("ACCOUNT: Found existing slot: %d - %u.%u.%u.%u/%u.%u.%u.%u\n", i,
117 NIPQUAD(ipt_account_tables[i].ip), NIPQUAD(ipt_account_tables[i].netmask));
70288420
TJ
118
119 if (ipt_account_tables[i].ip != ip || ipt_account_tables[i].netmask != netmask)
120 {
850cece6
TJ
121 printk("ACCOUNT: Table %s found, but IP/netmask mismatch. IP/netmask found: %u.%u.%u.%u/%u.%u.%u.%u\n",
122 name, NIPQUAD(ipt_account_tables[i].ip), NIPQUAD(ipt_account_tables[i].netmask));
70288420
TJ
123 return -1;
124 }
125
126 ipt_account_tables[i].refcount++;
127 DEBUGP("ACCOUNT: Refcount: %d\n", ipt_account_tables[i].refcount);
128 return i;
129 }
130 }
131
132 // Insert new table
133 for (i = 0; i < ACCOUNT_MAX_TABLES; i++)
134 {
135 // Found free slot
136 if (ipt_account_tables[i].name[0] == 0)
137 {
138 DEBUGP("ACCOUNT: Found free slot: %d\n", i);
139
140 strncpy (ipt_account_tables[i].name, name, ACCOUNT_TABLE_NAME_LEN-1);
141
142 ipt_account_tables[i].ip = ip;
143 ipt_account_tables[i].netmask = netmask;
144
850cece6
TJ
145 // Calculate netsize
146 unsigned int j, calc_mask, netsize=0;
70288420
TJ
147 calc_mask = htonl(netmask);
148 for (j = 31; j > 0; j--)
149 {
150 if (calc_mask&(1<<j))
850cece6 151 netsize++;
70288420
TJ
152 else
153 break;
154 }
850cece6
TJ
155
156 // Calculate depth from netsize
157 if (netsize >= 24)
158 ipt_account_tables[i].depth = 0;
159 else if (netsize >= 16)
160 ipt_account_tables[i].depth = 1;
161 else if(netsize >= 8)
162 ipt_account_tables[i].depth = 2;
163
164 printk("ACCOUNT: calculated netsize: %u -> ipt_account_table depth %u\n", netsize, ipt_account_tables[i].depth);
70288420
TJ
165
166 ipt_account_tables[i].refcount++;
167 if (!(ipt_account_tables[i].data = (void *)get_zeroed_page(GFP_KERNEL)))
168 {
850cece6 169 printk("ACCOUNT: out of memory for data of table: %s\n", name);
70288420
TJ
170 memset(&ipt_account_tables[i], 0, sizeof(struct ipt_account_table));
171 return -1;
172 }
850cece6 173
70288420
TJ
174 return i;
175 }
176 }
177
178 // No free slot found
179 printk("ACCOUNT: No free table slot found (max: %d). Please increase ACCOUNT_MAX_TABLES.\n", ACCOUNT_MAX_TABLES);
180 return -1;
181}
182
183static int ipt_account_checkentry(const char *tablename,
184 const struct ipt_entry *e,
185 void *targinfo,
186 unsigned int targinfosize,
187 unsigned int hook_mask)
188{
189 struct ipt_account_info *info = targinfo;
190
191 if (targinfosize != IPT_ALIGN(sizeof(struct ipt_account_info))) {
192 DEBUGP("ACCOUNT: targinfosize %u != %u\n",
193 targinfosize, IPT_ALIGN(sizeof(struct ipt_account_info)));
194 return 0;
195 }
196
850cece6 197 spin_lock_bh(&ipt_account_lock);
70288420
TJ
198 int table_nr = ipt_account_table_insert(info->table_name, info->net_ip, info->net_mask);
199 if (table_nr == -1)
200 {
201 printk("ACCOUNT: Table insert problem. Aborting\n");
850cece6 202 spin_unlock_bh(&ipt_account_lock);
70288420
TJ
203 return 0;
204 }
70288420
TJ
205 // Table nr caching so we don't have to do an extra string compare for every packet
206 info->table_nr = table_nr;
207
850cece6
TJ
208 spin_unlock_bh(&ipt_account_lock);
209
70288420
TJ
210 return 1;
211}
212
850cece6
TJ
213void ipt_account_deleteentry(void *targinfo, unsigned int targinfosize)
214{
215 unsigned int i;
216 struct ipt_account_info *info = targinfo;
217
218 if (targinfosize != IPT_ALIGN(sizeof(struct ipt_account_info))) {
219 DEBUGP("ACCOUNT: targinfosize %u != %u\n",
220 targinfosize, IPT_ALIGN(sizeof(struct ipt_account_info)));
221 }
222
223 spin_lock_bh(&ipt_account_lock);
224
225 DEBUGP("ACCOUNT: ipt_account_deleteentry called for table: %s (#%d)\n", info->table_name, info->table_nr);
226
227 info->table_nr = -1; // Set back to original state
228
229 // Look for table
230 for (i = 0; i < ACCOUNT_MAX_TABLES; i++)
231 {
232 if (strcmp(ipt_account_tables[i].name, info->table_name) == 0)
233 {
234 DEBUGP("ACCOUNT: Found table at slot: %d\n", i);
235
236 ipt_account_tables[i].refcount--;
237 DEBUGP("ACCOUNT: Refcount left: %d\n", ipt_account_tables[i].refcount);
238
239 // Table not needed anymore?
240 if (ipt_account_tables[i].refcount == 0)
241 {
242 DEBUGP("ACCOUNT: Destroying table at slot: %d\n", i);
243 ipt_account_data_free(ipt_account_tables[i].data, ipt_account_tables[i].depth);
244 memset(&ipt_account_tables[i], 0, sizeof(struct ipt_account_table));
245 }
246
247 spin_unlock_bh(&ipt_account_lock);
248 return;
249 }
250 }
251
252 // Table not found
253 printk("ACCOUNT: Table %s not found for destroy\n", info->table_name);
254 spin_unlock_bh(&ipt_account_lock);
255}
256
70288420 257static struct ipt_target ipt_account_reg
850cece6 258= { { NULL, NULL }, "ACCOUNT", ipt_account_target, ipt_account_checkentry, ipt_account_deleteentry,
70288420
TJ
259 THIS_MODULE };
260
261static int __init init(void)
262{
850cece6 263 if (!(ipt_account_tables = kmalloc(ACCOUNT_MAX_TABLES*sizeof(struct ipt_account_table), GFP_KERNEL)))
70288420
TJ
264 {
265 printk("ACCOUNT: Out of memory allocating account_tables structure");
266 return -EINVAL;
267 }
850cece6 268 memset(ipt_account_tables, 0, ACCOUNT_MAX_TABLES*sizeof(struct ipt_account_table));
70288420 269
850cece6 270 if (!(ipt_account_handles = kmalloc(ACCOUNT_MAX_HANDLES*sizeof(struct ipt_account_handle), GFP_KERNEL)))
70288420
TJ
271 {
272 printk("ACCOUNT: Out of memory allocating account_handles structure");
273 kfree (ipt_account_tables);
274 ipt_account_tables = NULL;
275 return -EINVAL;
276 }
850cece6 277 memset(ipt_account_handles, 0, ACCOUNT_MAX_HANDLES*sizeof(struct ipt_account_handle));
70288420
TJ
278
279 if (ipt_register_target(&ipt_account_reg))
280 return -EINVAL;
281
282 return 0;
283}
284
285static void __exit fini(void)
286{
287 ipt_unregister_target(&ipt_account_reg);
288
289 kfree(ipt_account_tables);
290 ipt_account_tables = NULL;
291
292 kfree(ipt_account_handles);
293 ipt_account_handles = NULL;
294}
295
296module_init(init);
297module_exit(fini);
298MODULE_LICENSE("GPL");