]> git.pld-linux.org Git - packages/kernel.git/blame - kernel-ipt_ACCOUNT.patch
- up to 2.6.17.28
[packages/kernel.git] / kernel-ipt_ACCOUNT.patch
CommitLineData
e6915d4c 1diff -uprN linux1/include/linux/netfilter_ipv4/ipt_ACCOUNT.h linux-2.6/include/linux/netfilter_ipv4/ipt_ACCOUNT.h
2--- linux1/include/linux/netfilter_ipv4/ipt_ACCOUNT.h 1970-01-01 01:00:00.000000000 +0100
3+++ linux-2.6/include/linux/netfilter_ipv4/ipt_ACCOUNT.h 2007-12-14 10:42:16.000000000 +0100
52578af9 4@@ -0,0 +1,100 @@
5+/***************************************************************************
e6915d4c 6+ * Copyright (C) 2004-2006 by Intra2net AG *
52578af9 7+ * opensource@intra2net.com *
8+ * *
9+ * This program is free software; you can redistribute it and/or modify *
10+ * it under the terms of the GNU General Public License *
11+ * version 2 as published by the Free Software Foundation; *
12+ * *
13+ ***************************************************************************/
14+
15+#ifndef _IPT_ACCOUNT_H
16+#define _IPT_ACCOUNT_H
17+
18+#define ACCOUNT_MAX_TABLES 128
19+#define ACCOUNT_TABLE_NAME_LEN 32
20+#define ACCOUNT_MAX_HANDLES 10
21+
22+/* Structure for the userspace part of ipt_ACCOUNT */
23+struct ipt_acc_info {
24+ u_int32_t net_ip;
25+ u_int32_t net_mask;
26+ char table_name[ACCOUNT_TABLE_NAME_LEN];
27+ int32_t table_nr;
28+};
29+
30+/* Internal table structure, generated by check_entry() */
31+struct ipt_acc_table {
32+ char name[ACCOUNT_TABLE_NAME_LEN]; /* name of the table */
33+ u_int32_t ip; /* base IP of network */
34+ u_int32_t netmask; /* netmask of the network */
35+ unsigned char depth; /* size of network:
36+ 0: 8 bit, 1: 16bit, 2: 24 bit */
37+ u_int32_t refcount; /* refcount of this table.
38+ if zero, destroy it */
39+ u_int32_t itemcount; /* number of IPs in this table */
40+ void *data; /* pointer to the actual data,
41+ depending on netmask */
42+};
43+
44+/* Internal handle structure */
45+struct ipt_acc_handle {
46+ u_int32_t ip; /* base IP of network. Used for
47+ caculating the final IP during
48+ get_data() */
49+ unsigned char depth; /* size of network. See above for
50+ details */
51+ u_int32_t itemcount; /* number of IPs in this table */
52+ void *data; /* pointer to the actual data,
53+ depending on size */
54+};
55+
56+/* Handle structure for communication with the userspace library */
57+struct ipt_acc_handle_sockopt {
58+ u_int32_t handle_nr; /* Used for HANDLE_FREE */
59+ char name[ACCOUNT_TABLE_NAME_LEN]; /* Used for HANDLE_PREPARE_READ/
60+ HANDLE_READ_FLUSH */
61+ u_int32_t itemcount; /* Used for HANDLE_PREPARE_READ/
62+ HANDLE_READ_FLUSH */
63+};
64+
65+/* Used for every IP entry
66+ Size is 16 bytes so that 256 (class C network) * 16
67+ fits in one kernel (zero) page */
68+struct ipt_acc_ip {
69+ u_int32_t src_packets;
70+ u_int32_t src_bytes;
71+ u_int32_t dst_packets;
72+ u_int32_t dst_bytes;
73+};
74+
75+/*
76+ Used for every IP when returning data
77+*/
78+struct ipt_acc_handle_ip {
79+ u_int32_t ip;
80+ u_int32_t src_packets;
81+ u_int32_t src_bytes;
82+ u_int32_t dst_packets;
83+ u_int32_t dst_bytes;
84+};
85+
86+/*
87+ The IPs are organized as an array so that direct slot
88+ calculations are possible.
89+ Only 8 bit networks are preallocated, 16/24 bit networks
90+ allocate their slots when needed -> very efficent.
91+*/
92+struct ipt_acc_mask_24 {
93+ struct ipt_acc_ip ip[256];
94+};
95+
96+struct ipt_acc_mask_16 {
97+ struct ipt_acc_mask_24 *mask_24[256];
98+};
99+
100+struct ipt_acc_mask_8 {
101+ struct ipt_acc_mask_16 *mask_16[256];
102+};
103+
104+#endif /*_IPT_ACCOUNT_H*/
e6915d4c 105diff -uprN linux1/net/ipv4/netfilter/ipt_ACCOUNT.c linux-2.6/net/ipv4/netfilter/ipt_ACCOUNT.c
106--- linux1/net/ipv4/netfilter/ipt_ACCOUNT.c 1970-01-01 01:00:00.000000000 +0100
107+++ linux-2.6/net/ipv4/netfilter/ipt_ACCOUNT.c 2008-03-10 11:39:42.000000000 +0100
108@@ -0,0 +1,1193 @@
52578af9 109+/***************************************************************************
110+ * This is a module which is used for counting packets. *
111+ * See http://www.intra2net.com/opensource/ipt_account *
112+ * for further information *
113+ * *
e6915d4c 114+ * Copyright (C) 2004-2007 by Intra2net AG *
52578af9 115+ * opensource@intra2net.com *
116+ * *
117+ * This program is free software; you can redistribute it and/or modify *
118+ * it under the terms of the GNU General Public License *
119+ * version 2 as published by the Free Software Foundation; *
120+ * *
121+ ***************************************************************************/
122+
123+#include <linux/module.h>
124+#include <linux/version.h>
125+#include <linux/skbuff.h>
126+#include <linux/ip.h>
127+#include <net/icmp.h>
128+#include <net/udp.h>
129+#include <net/tcp.h>
130+#include <linux/netfilter_ipv4/ip_tables.h>
9726d42d 131+#include <linux/semaphore.h>
52578af9 132+#include <linux/kernel.h>
133+#include <linux/mm.h>
134+#include <linux/string.h>
135+#include <linux/spinlock.h>
136+#include <asm/uaccess.h>
137+
138+#include <net/route.h>
139+#include <linux/netfilter_ipv4/ipt_ACCOUNT.h>
140+
141+#if 0
142+#define DEBUGP printk
143+#else
144+#define DEBUGP(format, args...)
145+#endif
146+
147+#if (PAGE_SIZE < 4096)
148+#error "ipt_ACCOUNT needs at least a PAGE_SIZE of 4096"
149+#endif
150+
151+static struct ipt_acc_table *ipt_acc_tables = NULL;
152+static struct ipt_acc_handle *ipt_acc_handles = NULL;
153+static void *ipt_acc_tmpbuf = NULL;
154+
155+/* Spinlock used for manipulating the current accounting tables/data */
156+static DEFINE_SPINLOCK(ipt_acc_lock);
157+/* Mutex (semaphore) used for manipulating userspace handles/snapshot data */
158+static struct semaphore ipt_acc_userspace_mutex;
159+
e6915d4c 160+/* Allocates a page and clears it */
161+static void *ipt_acc_zalloc_page(void)
162+{
163+ // Don't use get_zeroed_page until it's fixed in the kernel.
164+ // get_zeroed_page(GFP_ATOMIC)
165+ void *mem = (void *)__get_free_page(GFP_ATOMIC);
166+ if (mem) {
167+ memset (mem, 0, PAGE_SIZE);
168+ }
169+
170+ return mem;
171+}
52578af9 172+
173+/* Recursive free of all data structures */
174+static void ipt_acc_data_free(void *data, unsigned char depth)
175+{
176+ /* Empty data set */
177+ if (!data)
178+ return;
179+
180+ /* Free for 8 bit network */
181+ if (depth == 0) {
182+ free_page((unsigned long)data);
183+ return;
184+ }
185+
186+ /* Free for 16 bit network */
187+ if (depth == 1) {
188+ struct ipt_acc_mask_16 *mask_16 = (struct ipt_acc_mask_16 *)data;
189+ unsigned int b;
190+ for (b=0; b <= 255; b++) {
191+ if (mask_16->mask_24[b]) {
192+ free_page((unsigned long)mask_16->mask_24[b]);
193+ }
194+ }
195+ free_page((unsigned long)data);
196+ return;
197+ }
198+
199+ /* Free for 24 bit network */
200+ if (depth == 2) {
201+ unsigned int a, b;
202+ for (a=0; a <= 255; a++) {
203+ if (((struct ipt_acc_mask_8 *)data)->mask_16[a]) {
204+ struct ipt_acc_mask_16 *mask_16 = (struct ipt_acc_mask_16*)
205+ ((struct ipt_acc_mask_8 *)data)->mask_16[a];
206+
207+ for (b=0; b <= 255; b++) {
208+ if (mask_16->mask_24[b]) {
209+ free_page((unsigned long)mask_16->mask_24[b]);
210+ }
211+ }
212+ free_page((unsigned long)mask_16);
213+ }
214+ }
215+ free_page((unsigned long)data);
216+ return;
217+ }
218+
219+ printk("ACCOUNT: ipt_acc_data_free called with unknown depth: %d\n",
220+ depth);
221+ return;
222+}
223+
224+/* Look for existing table / insert new one.
225+ Return internal ID or -1 on error */
226+static int ipt_acc_table_insert(char *name, u_int32_t ip, u_int32_t netmask)
227+{
228+ unsigned int i;
229+
230+ DEBUGP("ACCOUNT: ipt_acc_table_insert: %s, %u.%u.%u.%u/%u.%u.%u.%u\n",
231+ name, NIPQUAD(ip), NIPQUAD(netmask));
232+
233+ /* Look for existing table */
234+ for (i = 0; i < ACCOUNT_MAX_TABLES; i++) {
235+ if (strncmp(ipt_acc_tables[i].name, name,
236+ ACCOUNT_TABLE_NAME_LEN) == 0) {
237+ DEBUGP("ACCOUNT: Found existing slot: %d - "
238+ "%u.%u.%u.%u/%u.%u.%u.%u\n", i,
239+ NIPQUAD(ipt_acc_tables[i].ip),
240+ NIPQUAD(ipt_acc_tables[i].netmask));
241+
242+ if (ipt_acc_tables[i].ip != ip
243+ || ipt_acc_tables[i].netmask != netmask) {
244+ printk("ACCOUNT: Table %s found, but IP/netmask mismatch. "
245+ "IP/netmask found: %u.%u.%u.%u/%u.%u.%u.%u\n",
246+ name, NIPQUAD(ipt_acc_tables[i].ip),
247+ NIPQUAD(ipt_acc_tables[i].netmask));
248+ return -1;
249+ }
250+
251+ ipt_acc_tables[i].refcount++;
252+ DEBUGP("ACCOUNT: Refcount: %d\n", ipt_acc_tables[i].refcount);
253+ return i;
254+ }
255+ }
256+
257+ /* Insert new table */
258+ for (i = 0; i < ACCOUNT_MAX_TABLES; i++) {
259+ /* Found free slot */
260+ if (ipt_acc_tables[i].name[0] == 0) {
261+ unsigned int netsize=0;
262+ u_int32_t calc_mask;
263+ int j; /* needs to be signed, otherwise we risk endless loop */
264+
265+ DEBUGP("ACCOUNT: Found free slot: %d\n", i);
266+ strncpy (ipt_acc_tables[i].name, name, ACCOUNT_TABLE_NAME_LEN-1);
267+
268+ ipt_acc_tables[i].ip = ip;
269+ ipt_acc_tables[i].netmask = netmask;
270+
271+ /* Calculate netsize */
272+ calc_mask = htonl(netmask);
273+ for (j = 31; j >= 0; j--) {
274+ if (calc_mask&(1<<j))
275+ netsize++;
276+ else
277+ break;
278+ }
279+
280+ /* Calculate depth from netsize */
281+ if (netsize >= 24)
282+ ipt_acc_tables[i].depth = 0;
283+ else if (netsize >= 16)
284+ ipt_acc_tables[i].depth = 1;
285+ else if(netsize >= 8)
286+ ipt_acc_tables[i].depth = 2;
287+
288+ DEBUGP("ACCOUNT: calculated netsize: %u -> "
289+ "ipt_acc_table depth %u\n", netsize,
290+ ipt_acc_tables[i].depth);
291+
292+ ipt_acc_tables[i].refcount++;
293+ if ((ipt_acc_tables[i].data
e6915d4c 294+ = ipt_acc_zalloc_page()) == NULL) {
52578af9 295+ printk("ACCOUNT: out of memory for data of table: %s\n", name);
296+ memset(&ipt_acc_tables[i], 0,
297+ sizeof(struct ipt_acc_table));
298+ return -1;
299+ }
300+
301+ return i;
302+ }
303+ }
304+
305+ /* No free slot found */
306+ printk("ACCOUNT: No free table slot found (max: %d). "
307+ "Please increase ACCOUNT_MAX_TABLES.\n", ACCOUNT_MAX_TABLES);
308+ return -1;
309+}
310+
e6915d4c 311+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
312+static bool ipt_acc_checkentry(const char *tablename,
313+#else
52578af9 314+static int ipt_acc_checkentry(const char *tablename,
e6915d4c 315+#endif
52578af9 316+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
317+ const void *e,
318+#else
319+ const struct ipt_entry *e,
320+#endif
321+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
322+ const struct xt_target *target,
323+#endif
324+ void *targinfo,
325+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
326+ unsigned int targinfosize,
327+#endif
328+ unsigned int hook_mask)
329+{
330+ struct ipt_acc_info *info = targinfo;
331+ int table_nr;
332+
333+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
334+ if (targinfosize != IPT_ALIGN(sizeof(struct ipt_acc_info))) {
335+ DEBUGP("ACCOUNT: targinfosize %u != %u\n",
336+ targinfosize, IPT_ALIGN(sizeof(struct ipt_acc_info)));
337+ return 0;
338+ }
339+#endif
340+
341+ spin_lock_bh(&ipt_acc_lock);
342+ table_nr = ipt_acc_table_insert(info->table_name, info->net_ip,
343+ info->net_mask);
344+ spin_unlock_bh(&ipt_acc_lock);
345+
346+ if (table_nr == -1) {
347+ printk("ACCOUNT: Table insert problem. Aborting\n");
e6915d4c 348+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
349+ return false;
350+#else
52578af9 351+ return 0;
e6915d4c 352+#endif
52578af9 353+ }
354+ /* Table nr caching so we don't have to do an extra string compare
355+ for every packet */
356+ info->table_nr = table_nr;
357+
e6915d4c 358+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
359+ return true;
360+#else
52578af9 361+ return 1;
e6915d4c 362+#endif
52578af9 363+}
364+
365+static void ipt_acc_destroy(
366+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
367+ const struct xt_target *target,
368+#endif
369+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)
370+ void *targinfo)
371+#else
372+ void *targinfo,
373+ unsigned int targinfosize)
374+#endif
375+{
376+ unsigned int i;
377+ struct ipt_acc_info *info = targinfo;
378+
379+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
380+ if (targinfosize != IPT_ALIGN(sizeof(struct ipt_acc_info))) {
381+ DEBUGP("ACCOUNT: targinfosize %u != %u\n",
382+ targinfosize, IPT_ALIGN(sizeof(struct ipt_acc_info)));
383+ }
384+#endif
385+
386+ spin_lock_bh(&ipt_acc_lock);
387+
388+ DEBUGP("ACCOUNT: ipt_acc_deleteentry called for table: %s (#%d)\n",
389+ info->table_name, info->table_nr);
390+
391+ info->table_nr = -1; /* Set back to original state */
392+
393+ /* Look for table */
394+ for (i = 0; i < ACCOUNT_MAX_TABLES; i++) {
395+ if (strncmp(ipt_acc_tables[i].name, info->table_name,
396+ ACCOUNT_TABLE_NAME_LEN) == 0) {
397+ DEBUGP("ACCOUNT: Found table at slot: %d\n", i);
398+
399+ ipt_acc_tables[i].refcount--;
400+ DEBUGP("ACCOUNT: Refcount left: %d\n",
401+ ipt_acc_tables[i].refcount);
402+
403+ /* Table not needed anymore? */
404+ if (ipt_acc_tables[i].refcount == 0) {
405+ DEBUGP("ACCOUNT: Destroying table at slot: %d\n", i);
406+ ipt_acc_data_free(ipt_acc_tables[i].data,
407+ ipt_acc_tables[i].depth);
408+ memset(&ipt_acc_tables[i], 0,
409+ sizeof(struct ipt_acc_table));
410+ }
411+
412+ spin_unlock_bh(&ipt_acc_lock);
413+ return;
414+ }
415+ }
416+
417+ /* Table not found */
418+ printk("ACCOUNT: Table %s not found for destroy\n", info->table_name);
419+ spin_unlock_bh(&ipt_acc_lock);
420+}
421+
422+static void ipt_acc_depth0_insert(struct ipt_acc_mask_24 *mask_24,
423+ u_int32_t net_ip, u_int32_t netmask,
424+ u_int32_t src_ip, u_int32_t dst_ip,
425+ u_int32_t size, u_int32_t *itemcount)
426+{
427+ unsigned char is_src = 0, is_dst = 0, src_slot, dst_slot;
428+ char is_src_new_ip = 0, is_dst_new_ip = 0; /* Check if this entry is new */
429+
430+ DEBUGP("ACCOUNT: ipt_acc_depth0_insert: %u.%u.%u.%u/%u.%u.%u.%u "
431+ "for net %u.%u.%u.%u/%u.%u.%u.%u, size: %u\n", NIPQUAD(src_ip),
432+ NIPQUAD(dst_ip), NIPQUAD(net_ip), NIPQUAD(netmask), size);
433+
434+ /* Check if src/dst is inside our network. */
435+ /* Special: net_ip = 0.0.0.0/0 gets stored as src in slot 0 */
436+ if (!netmask)
437+ src_ip = 0;
438+ if ((net_ip&netmask) == (src_ip&netmask))
439+ is_src = 1;
440+ if ((net_ip&netmask) == (dst_ip&netmask) && netmask)
441+ is_dst = 1;
442+
443+ if (!is_src && !is_dst) {
444+ DEBUGP("ACCOUNT: Skipping packet %u.%u.%u.%u/%u.%u.%u.%u "
445+ "for net %u.%u.%u.%u/%u.%u.%u.%u\n", NIPQUAD(src_ip),
446+ NIPQUAD(dst_ip), NIPQUAD(net_ip), NIPQUAD(netmask));
447+ return;
448+ }
449+
450+ /* Calculate array positions */
451+ src_slot = (unsigned char)((src_ip&0xFF000000) >> 24);
452+ dst_slot = (unsigned char)((dst_ip&0xFF000000) >> 24);
453+
454+ /* Increase size counters */
455+ if (is_src) {
456+ /* Calculate network slot */
457+ DEBUGP("ACCOUNT: Calculated SRC 8 bit network slot: %d\n", src_slot);
458+ if (!mask_24->ip[src_slot].src_packets
459+ && !mask_24->ip[src_slot].dst_packets)
460+ is_src_new_ip = 1;
461+
462+ mask_24->ip[src_slot].src_packets++;
463+ mask_24->ip[src_slot].src_bytes+=size;
464+ }
465+ if (is_dst) {
466+ DEBUGP("ACCOUNT: Calculated DST 8 bit network slot: %d\n", dst_slot);
467+ if (!mask_24->ip[dst_slot].src_packets
468+ && !mask_24->ip[dst_slot].dst_packets)
469+ is_dst_new_ip = 1;
470+
471+ mask_24->ip[dst_slot].dst_packets++;
472+ mask_24->ip[dst_slot].dst_bytes+=size;
473+ }
474+
475+ /* Increase itemcounter */
476+ DEBUGP("ACCOUNT: Itemcounter before: %d\n", *itemcount);
477+ if (src_slot == dst_slot) {
478+ if (is_src_new_ip || is_dst_new_ip) {
479+ DEBUGP("ACCOUNT: src_slot == dst_slot: %d, %d\n",
480+ is_src_new_ip, is_dst_new_ip);
481+ (*itemcount)++;
482+ }
483+ } else {
484+ if (is_src_new_ip) {
485+ DEBUGP("ACCOUNT: New src_ip: %u.%u.%u.%u\n", NIPQUAD(src_ip));
486+ (*itemcount)++;
487+ }
488+ if (is_dst_new_ip) {
489+ DEBUGP("ACCOUNT: New dst_ip: %u.%u.%u.%u\n", NIPQUAD(dst_ip));
490+ (*itemcount)++;
491+ }
492+ }
493+ DEBUGP("ACCOUNT: Itemcounter after: %d\n", *itemcount);
494+}
495+
496+static void ipt_acc_depth1_insert(struct ipt_acc_mask_16 *mask_16,
497+ u_int32_t net_ip, u_int32_t netmask,
498+ u_int32_t src_ip, u_int32_t dst_ip,
499+ u_int32_t size, u_int32_t *itemcount)
500+{
501+ /* Do we need to process src IP? */
502+ if ((net_ip&netmask) == (src_ip&netmask)) {
503+ unsigned char slot = (unsigned char)((src_ip&0x00FF0000) >> 16);
504+ DEBUGP("ACCOUNT: Calculated SRC 16 bit network slot: %d\n", slot);
505+
506+ /* Do we need to create a new mask_24 bucket? */
507+ if (!mask_16->mask_24[slot] && (mask_16->mask_24[slot] =
e6915d4c 508+ ipt_acc_zalloc_page()) == NULL) {
52578af9 509+ printk("ACCOUNT: Can't process packet because out of memory!\n");
510+ return;
511+ }
512+
513+ ipt_acc_depth0_insert((struct ipt_acc_mask_24 *)mask_16->mask_24[slot],
514+ net_ip, netmask, src_ip, 0, size, itemcount);
515+ }
516+
517+ /* Do we need to process dst IP? */
518+ if ((net_ip&netmask) == (dst_ip&netmask)) {
519+ unsigned char slot = (unsigned char)((dst_ip&0x00FF0000) >> 16);
520+ DEBUGP("ACCOUNT: Calculated DST 16 bit network slot: %d\n", slot);
521+
522+ /* Do we need to create a new mask_24 bucket? */
523+ if (!mask_16->mask_24[slot] && (mask_16->mask_24[slot]
e6915d4c 524+ = ipt_acc_zalloc_page()) == NULL) {
52578af9 525+ printk("ACCOUT: Can't process packet because out of memory!\n");
526+ return;
527+ }
528+
529+ ipt_acc_depth0_insert((struct ipt_acc_mask_24 *)mask_16->mask_24[slot],
530+ net_ip, netmask, 0, dst_ip, size, itemcount);
531+ }
532+}
533+
534+static void ipt_acc_depth2_insert(struct ipt_acc_mask_8 *mask_8,
535+ u_int32_t net_ip, u_int32_t netmask,
536+ u_int32_t src_ip, u_int32_t dst_ip,
537+ u_int32_t size, u_int32_t *itemcount)
538+{
539+ /* Do we need to process src IP? */
540+ if ((net_ip&netmask) == (src_ip&netmask)) {
541+ unsigned char slot = (unsigned char)((src_ip&0x0000FF00) >> 8);
542+ DEBUGP("ACCOUNT: Calculated SRC 24 bit network slot: %d\n", slot);
543+
544+ /* Do we need to create a new mask_24 bucket? */
545+ if (!mask_8->mask_16[slot] && (mask_8->mask_16[slot]
e6915d4c 546+ = ipt_acc_zalloc_page()) == NULL) {
52578af9 547+ printk("ACCOUNT: Can't process packet because out of memory!\n");
548+ return;
549+ }
550+
551+ ipt_acc_depth1_insert((struct ipt_acc_mask_16 *)mask_8->mask_16[slot],
552+ net_ip, netmask, src_ip, 0, size, itemcount);
553+ }
554+
555+ /* Do we need to process dst IP? */
556+ if ((net_ip&netmask) == (dst_ip&netmask)) {
557+ unsigned char slot = (unsigned char)((dst_ip&0x0000FF00) >> 8);
558+ DEBUGP("ACCOUNT: Calculated DST 24 bit network slot: %d\n", slot);
559+
560+ /* Do we need to create a new mask_24 bucket? */
561+ if (!mask_8->mask_16[slot] && (mask_8->mask_16[slot]
e6915d4c 562+ = ipt_acc_zalloc_page()) == NULL) {
52578af9 563+ printk("ACCOUNT: Can't process packet because out of memory!\n");
564+ return;
565+ }
566+
567+ ipt_acc_depth1_insert((struct ipt_acc_mask_16 *)mask_8->mask_16[slot],
568+ net_ip, netmask, 0, dst_ip, size, itemcount);
569+ }
570+}
571+
e6915d4c 572+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
573+static unsigned int ipt_acc_target(struct sk_buff *skb,
574+#else
52578af9 575+static unsigned int ipt_acc_target(struct sk_buff **pskb,
e6915d4c 576+#endif
52578af9 577+ const struct net_device *in,
578+ const struct net_device *out,
579+ unsigned int hooknum,
580+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
581+ const struct xt_target *target,
582+#endif
583+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)
584+ const void *targinfo)
585+#else
586+ const void *targinfo,
587+ void *userinfo)
588+#endif
589+{
590+ const struct ipt_acc_info *info =
591+ (const struct ipt_acc_info *)targinfo;
e6915d4c 592+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
593+ u_int32_t src_ip = ip_hdr(skb)->saddr;
594+ u_int32_t dst_ip = ip_hdr(skb)->daddr;
595+ u_int32_t size = ntohs(ip_hdr(skb)->tot_len);
596+#else
52578af9 597+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
598+ u_int32_t src_ip = ip_hdr(*pskb)->saddr;
599+ u_int32_t dst_ip = ip_hdr(*pskb)->daddr;
600+ u_int32_t size = ntohs(ip_hdr(*pskb)->tot_len);
601+#else
602+ u_int32_t src_ip = (*pskb)->nh.iph->saddr;
603+ u_int32_t dst_ip = (*pskb)->nh.iph->daddr;
604+ u_int32_t size = ntohs((*pskb)->nh.iph->tot_len);
605+#endif
e6915d4c 606+#endif
52578af9 607+
608+ spin_lock_bh(&ipt_acc_lock);
609+
610+ if (ipt_acc_tables[info->table_nr].name[0] == 0) {
611+ printk("ACCOUNT: ipt_acc_target: Invalid table id %u. "
612+ "IPs %u.%u.%u.%u/%u.%u.%u.%u\n", info->table_nr,
613+ NIPQUAD(src_ip), NIPQUAD(dst_ip));
614+ spin_unlock_bh(&ipt_acc_lock);
615+ return IPT_CONTINUE;
616+ }
617+
618+ /* 8 bit network or "any" network */
619+ if (ipt_acc_tables[info->table_nr].depth == 0) {
620+ /* Count packet and check if the IP is new */
621+ ipt_acc_depth0_insert(
622+ (struct ipt_acc_mask_24 *)ipt_acc_tables[info->table_nr].data,
623+ ipt_acc_tables[info->table_nr].ip,
624+ ipt_acc_tables[info->table_nr].netmask,
625+ src_ip, dst_ip, size, &ipt_acc_tables[info->table_nr].itemcount);
626+ spin_unlock_bh(&ipt_acc_lock);
627+ return IPT_CONTINUE;
628+ }
629+
630+ /* 16 bit network */
631+ if (ipt_acc_tables[info->table_nr].depth == 1) {
632+ ipt_acc_depth1_insert(
633+ (struct ipt_acc_mask_16 *)ipt_acc_tables[info->table_nr].data,
634+ ipt_acc_tables[info->table_nr].ip,
635+ ipt_acc_tables[info->table_nr].netmask,
636+ src_ip, dst_ip, size, &ipt_acc_tables[info->table_nr].itemcount);
637+ spin_unlock_bh(&ipt_acc_lock);
638+ return IPT_CONTINUE;
639+ }
640+
641+ /* 24 bit network */
642+ if (ipt_acc_tables[info->table_nr].depth == 2) {
643+ ipt_acc_depth2_insert(
644+ (struct ipt_acc_mask_8 *)ipt_acc_tables[info->table_nr].data,
645+ ipt_acc_tables[info->table_nr].ip,
646+ ipt_acc_tables[info->table_nr].netmask,
647+ src_ip, dst_ip, size, &ipt_acc_tables[info->table_nr].itemcount);
648+ spin_unlock_bh(&ipt_acc_lock);
649+ return IPT_CONTINUE;
650+ }
651+
652+ printk("ACCOUNT: ipt_acc_target: Unable to process packet. "
653+ "Table id %u. IPs %u.%u.%u.%u/%u.%u.%u.%u\n",
654+ info->table_nr, NIPQUAD(src_ip), NIPQUAD(dst_ip));
655+
656+ spin_unlock_bh(&ipt_acc_lock);
657+ return IPT_CONTINUE;
658+}
659+
660+/*
661+ Functions dealing with "handles":
662+ Handles are snapshots of a accounting state.
663+
664+ read snapshots are only for debugging the code
665+ and are very expensive concerning speed/memory
666+ compared to read_and_flush.
667+
668+ The functions aren't protected by spinlocks themselves
669+ as this is done in the ioctl part of the code.
670+*/
671+
672+/*
673+ Find a free handle slot. Normally only one should be used,
674+ but there could be two or more applications accessing the data
675+ at the same time.
676+*/
677+static int ipt_acc_handle_find_slot(void)
678+{
679+ unsigned int i;
680+ /* Insert new table */
681+ for (i = 0; i < ACCOUNT_MAX_HANDLES; i++) {
682+ /* Found free slot */
683+ if (ipt_acc_handles[i].data == NULL) {
684+ /* Don't "mark" data as used as we are protected by a spinlock
685+ by the calling function. handle_find_slot() is only a function
686+ to prevent code duplication. */
687+ return i;
688+ }
689+ }
690+
691+ /* No free slot found */
692+ printk("ACCOUNT: No free handle slot found (max: %u). "
693+ "Please increase ACCOUNT_MAX_HANDLES.\n", ACCOUNT_MAX_HANDLES);
694+ return -1;
695+}
696+
697+static int ipt_acc_handle_free(unsigned int handle)
698+{
699+ if (handle >= ACCOUNT_MAX_HANDLES) {
700+ printk("ACCOUNT: Invalid handle for ipt_acc_handle_free() specified:"
701+ " %u\n", handle);
702+ return -EINVAL;
703+ }
704+
705+ ipt_acc_data_free(ipt_acc_handles[handle].data,
706+ ipt_acc_handles[handle].depth);
707+ memset (&ipt_acc_handles[handle], 0, sizeof (struct ipt_acc_handle));
708+ return 0;
709+}
710+
711+/* Prepare data for read without flush. Use only for debugging!
712+ Real applications should use read&flush as it's way more efficent */
713+static int ipt_acc_handle_prepare_read(char *tablename,
714+ struct ipt_acc_handle *dest, u_int32_t *count)
715+{
716+ int table_nr=-1;
717+ unsigned char depth;
718+
719+ for (table_nr = 0; table_nr < ACCOUNT_MAX_TABLES; table_nr++)
720+ if (strncmp(ipt_acc_tables[table_nr].name, tablename,
721+ ACCOUNT_TABLE_NAME_LEN) == 0)
722+ break;
723+
724+ if (table_nr == ACCOUNT_MAX_TABLES) {
725+ printk("ACCOUNT: ipt_acc_handle_prepare_read(): "
726+ "Table %s not found\n", tablename);
727+ return -1;
728+ }
729+
730+ /* Fill up handle structure */
731+ dest->ip = ipt_acc_tables[table_nr].ip;
732+ dest->depth = ipt_acc_tables[table_nr].depth;
733+ dest->itemcount = ipt_acc_tables[table_nr].itemcount;
734+
735+ /* allocate "root" table */
e6915d4c 736+ if ((dest->data = ipt_acc_zalloc_page()) == NULL) {
52578af9 737+ printk("ACCOUNT: out of memory for root table "
738+ "in ipt_acc_handle_prepare_read()\n");
739+ return -1;
740+ }
741+
742+ /* Recursive copy of complete data structure */
743+ depth = dest->depth;
744+ if (depth == 0) {
745+ memcpy(dest->data,
746+ ipt_acc_tables[table_nr].data,
747+ sizeof(struct ipt_acc_mask_24));
748+ } else if (depth == 1) {
749+ struct ipt_acc_mask_16 *src_16 =
750+ (struct ipt_acc_mask_16 *)ipt_acc_tables[table_nr].data;
751+ struct ipt_acc_mask_16 *network_16 =
752+ (struct ipt_acc_mask_16 *)dest->data;
753+ unsigned int b;
754+
755+ for (b = 0; b <= 255; b++) {
756+ if (src_16->mask_24[b]) {
757+ if ((network_16->mask_24[b] =
e6915d4c 758+ ipt_acc_zalloc_page()) == NULL) {
52578af9 759+ printk("ACCOUNT: out of memory during copy of 16 bit "
760+ "network in ipt_acc_handle_prepare_read()\n");
761+ ipt_acc_data_free(dest->data, depth);
762+ return -1;
763+ }
764+
765+ memcpy(network_16->mask_24[b], src_16->mask_24[b],
766+ sizeof(struct ipt_acc_mask_24));
767+ }
768+ }
769+ } else if(depth == 2) {
770+ struct ipt_acc_mask_8 *src_8 =
771+ (struct ipt_acc_mask_8 *)ipt_acc_tables[table_nr].data;
772+ struct ipt_acc_mask_8 *network_8 =
773+ (struct ipt_acc_mask_8 *)dest->data;
774+ struct ipt_acc_mask_16 *src_16, *network_16;
775+ unsigned int a, b;
776+
777+ for (a = 0; a <= 255; a++) {
778+ if (src_8->mask_16[a]) {
779+ if ((network_8->mask_16[a] =
e6915d4c 780+ ipt_acc_zalloc_page()) == NULL) {
52578af9 781+ printk("ACCOUNT: out of memory during copy of 24 bit network"
782+ " in ipt_acc_handle_prepare_read()\n");
783+ ipt_acc_data_free(dest->data, depth);
784+ return -1;
785+ }
786+
787+ memcpy(network_8->mask_16[a], src_8->mask_16[a],
788+ sizeof(struct ipt_acc_mask_16));
789+
790+ src_16 = src_8->mask_16[a];
791+ network_16 = network_8->mask_16[a];
792+
793+ for (b = 0; b <= 255; b++) {
794+ if (src_16->mask_24[b]) {
795+ if ((network_16->mask_24[b] =
e6915d4c 796+ ipt_acc_zalloc_page()) == NULL) {
52578af9 797+ printk("ACCOUNT: out of memory during copy of 16 bit"
798+ " network in ipt_acc_handle_prepare_read()\n");
799+ ipt_acc_data_free(dest->data, depth);
800+ return -1;
801+ }
802+
803+ memcpy(network_16->mask_24[b], src_16->mask_24[b],
804+ sizeof(struct ipt_acc_mask_24));
805+ }
806+ }
807+ }
808+ }
809+ }
810+
811+ *count = ipt_acc_tables[table_nr].itemcount;
812+
813+ return 0;
814+}
815+
816+/* Prepare data for read and flush it */
817+static int ipt_acc_handle_prepare_read_flush(char *tablename,
818+ struct ipt_acc_handle *dest, u_int32_t *count)
819+{
820+ int table_nr;
821+ void *new_data_page;
822+
823+ for (table_nr = 0; table_nr < ACCOUNT_MAX_TABLES; table_nr++)
824+ if (strncmp(ipt_acc_tables[table_nr].name, tablename,
825+ ACCOUNT_TABLE_NAME_LEN) == 0)
826+ break;
827+
828+ if (table_nr == ACCOUNT_MAX_TABLES) {
829+ printk("ACCOUNT: ipt_acc_handle_prepare_read_flush(): "
830+ "Table %s not found\n", tablename);
831+ return -1;
832+ }
833+
834+ /* Try to allocate memory */
e6915d4c 835+ if (!(new_data_page = ipt_acc_zalloc_page())) {
52578af9 836+ printk("ACCOUNT: ipt_acc_handle_prepare_read_flush(): "
837+ "Out of memory!\n");
838+ return -1;
839+ }
840+
841+ /* Fill up handle structure */
842+ dest->ip = ipt_acc_tables[table_nr].ip;
843+ dest->depth = ipt_acc_tables[table_nr].depth;
844+ dest->itemcount = ipt_acc_tables[table_nr].itemcount;
845+ dest->data = ipt_acc_tables[table_nr].data;
846+ *count = ipt_acc_tables[table_nr].itemcount;
847+
848+ /* "Flush" table data */
849+ ipt_acc_tables[table_nr].data = new_data_page;
850+ ipt_acc_tables[table_nr].itemcount = 0;
851+
852+ return 0;
853+}
854+
855+/* Copy 8 bit network data into a prepared buffer.
856+ We only copy entries != 0 to increase performance.
857+*/
858+static int ipt_acc_handle_copy_data(void *to_user, unsigned long *to_user_pos,
859+ unsigned long *tmpbuf_pos,
860+ struct ipt_acc_mask_24 *data,
861+ u_int32_t net_ip, u_int32_t net_OR_mask)
862+{
863+ struct ipt_acc_handle_ip handle_ip;
864+ size_t handle_ip_size = sizeof (struct ipt_acc_handle_ip);
865+ unsigned int i;
866+
867+ for (i = 0; i <= 255; i++) {
868+ if (data->ip[i].src_packets || data->ip[i].dst_packets) {
869+ handle_ip.ip = net_ip | net_OR_mask | (i<<24);
870+
871+ handle_ip.src_packets = data->ip[i].src_packets;
872+ handle_ip.src_bytes = data->ip[i].src_bytes;
873+ handle_ip.dst_packets = data->ip[i].dst_packets;
874+ handle_ip.dst_bytes = data->ip[i].dst_bytes;
875+
876+ /* Temporary buffer full? Flush to userspace */
877+ if (*tmpbuf_pos+handle_ip_size >= PAGE_SIZE) {
878+ if (copy_to_user(to_user + *to_user_pos, ipt_acc_tmpbuf,
879+ *tmpbuf_pos))
880+ return -EFAULT;
881+ *to_user_pos = *to_user_pos + *tmpbuf_pos;
882+ *tmpbuf_pos = 0;
883+ }
884+ memcpy(ipt_acc_tmpbuf+*tmpbuf_pos, &handle_ip, handle_ip_size);
885+ *tmpbuf_pos += handle_ip_size;
886+ }
887+ }
888+
889+ return 0;
890+}
891+
892+/* Copy the data from our internal structure
893+ We only copy entries != 0 to increase performance.
894+ Overwrites ipt_acc_tmpbuf.
895+*/
896+static int ipt_acc_handle_get_data(u_int32_t handle, void *to_user)
897+{
898+ unsigned long to_user_pos=0, tmpbuf_pos=0;
899+ u_int32_t net_ip;
900+ unsigned char depth;
901+
902+ if (handle >= ACCOUNT_MAX_HANDLES) {
903+ printk("ACCOUNT: invalid handle for ipt_acc_handle_get_data() "
904+ "specified: %u\n", handle);
905+ return -1;
906+ }
907+
908+ if (ipt_acc_handles[handle].data == NULL) {
909+ printk("ACCOUNT: handle %u is BROKEN: Contains no data\n", handle);
910+ return -1;
911+ }
912+
913+ net_ip = ipt_acc_handles[handle].ip;
914+ depth = ipt_acc_handles[handle].depth;
915+
916+ /* 8 bit network */
917+ if (depth == 0) {
918+ struct ipt_acc_mask_24 *network =
919+ (struct ipt_acc_mask_24*)ipt_acc_handles[handle].data;
920+ if (ipt_acc_handle_copy_data(to_user, &to_user_pos, &tmpbuf_pos,
921+ network, net_ip, 0))
922+ return -1;
923+
924+ /* Flush remaining data to userspace */
925+ if (tmpbuf_pos)
926+ if (copy_to_user(to_user+to_user_pos, ipt_acc_tmpbuf, tmpbuf_pos))
927+ return -1;
928+
929+ return 0;
930+ }
931+
932+ /* 16 bit network */
933+ if (depth == 1) {
934+ struct ipt_acc_mask_16 *network_16 =
935+ (struct ipt_acc_mask_16*)ipt_acc_handles[handle].data;
936+ unsigned int b;
937+ for (b = 0; b <= 255; b++) {
938+ if (network_16->mask_24[b]) {
939+ struct ipt_acc_mask_24 *network =
940+ (struct ipt_acc_mask_24*)network_16->mask_24[b];
941+ if (ipt_acc_handle_copy_data(to_user, &to_user_pos,
942+ &tmpbuf_pos, network, net_ip, (b << 16)))
943+ return -1;
944+ }
945+ }
946+
947+ /* Flush remaining data to userspace */
948+ if (tmpbuf_pos)
949+ if (copy_to_user(to_user+to_user_pos, ipt_acc_tmpbuf, tmpbuf_pos))
950+ return -1;
951+
952+ return 0;
953+ }
954+
955+ /* 24 bit network */
956+ if (depth == 2) {
957+ struct ipt_acc_mask_8 *network_8 =
958+ (struct ipt_acc_mask_8*)ipt_acc_handles[handle].data;
959+ unsigned int a, b;
960+ for (a = 0; a <= 255; a++) {
961+ if (network_8->mask_16[a]) {
962+ struct ipt_acc_mask_16 *network_16 =
963+ (struct ipt_acc_mask_16*)network_8->mask_16[a];
964+ for (b = 0; b <= 255; b++) {
965+ if (network_16->mask_24[b]) {
966+ struct ipt_acc_mask_24 *network =
967+ (struct ipt_acc_mask_24*)network_16->mask_24[b];
968+ if (ipt_acc_handle_copy_data(to_user,
969+ &to_user_pos, &tmpbuf_pos,
970+ network, net_ip, (a << 8) | (b << 16)))
971+ return -1;
972+ }
973+ }
974+ }
975+ }
976+
977+ /* Flush remaining data to userspace */
978+ if (tmpbuf_pos)
979+ if (copy_to_user(to_user+to_user_pos, ipt_acc_tmpbuf, tmpbuf_pos))
980+ return -1;
981+
982+ return 0;
983+ }
984+
985+ return -1;
986+}
987+
988+static int ipt_acc_set_ctl(struct sock *sk, int cmd,
989+ void *user, unsigned int len)
990+{
991+ struct ipt_acc_handle_sockopt handle;
992+ int ret = -EINVAL;
993+
994+ if (!capable(CAP_NET_ADMIN))
995+ return -EPERM;
996+
997+ switch (cmd) {
998+ case IPT_SO_SET_ACCOUNT_HANDLE_FREE:
999+ if (len != sizeof(struct ipt_acc_handle_sockopt)) {
e6915d4c 1000+ printk("ACCOUNT: ipt_acc_set_ctl: wrong data size (%u != %zu) "
52578af9 1001+ "for IPT_SO_SET_HANDLE_FREE\n",
1002+ len, sizeof(struct ipt_acc_handle_sockopt));
1003+ break;
1004+ }
1005+
1006+ if (copy_from_user (&handle, user, len)) {
1007+ printk("ACCOUNT: ipt_acc_set_ctl: copy_from_user failed for "
1008+ "IPT_SO_SET_HANDLE_FREE\n");
1009+ break;
1010+ }
1011+
1012+ down(&ipt_acc_userspace_mutex);
1013+ ret = ipt_acc_handle_free(handle.handle_nr);
1014+ up(&ipt_acc_userspace_mutex);
1015+ break;
1016+ case IPT_SO_SET_ACCOUNT_HANDLE_FREE_ALL: {
1017+ unsigned int i;
1018+ down(&ipt_acc_userspace_mutex);
1019+ for (i = 0; i < ACCOUNT_MAX_HANDLES; i++)
1020+ ipt_acc_handle_free(i);
1021+ up(&ipt_acc_userspace_mutex);
1022+ ret = 0;
1023+ break;
1024+ }
1025+ default:
1026+ printk("ACCOUNT: ipt_acc_set_ctl: unknown request %i\n", cmd);
1027+ }
1028+
1029+ return ret;
1030+}
1031+
1032+static int ipt_acc_get_ctl(struct sock *sk, int cmd, void *user, int *len)
1033+{
1034+ struct ipt_acc_handle_sockopt handle;
1035+ int ret = -EINVAL;
1036+
1037+ if (!capable(CAP_NET_ADMIN))
1038+ return -EPERM;
1039+
1040+ switch (cmd) {
1041+ case IPT_SO_GET_ACCOUNT_PREPARE_READ_FLUSH:
1042+ case IPT_SO_GET_ACCOUNT_PREPARE_READ: {
1043+ struct ipt_acc_handle dest;
1044+
1045+ if (*len < sizeof(struct ipt_acc_handle_sockopt)) {
e6915d4c 1046+ printk("ACCOUNT: ipt_acc_get_ctl: wrong data size (%u != %zu) "
52578af9 1047+ "for IPT_SO_GET_ACCOUNT_PREPARE_READ/READ_FLUSH\n",
1048+ *len, sizeof(struct ipt_acc_handle_sockopt));
1049+ break;
1050+ }
1051+
1052+ if (copy_from_user (&handle, user,
1053+ sizeof(struct ipt_acc_handle_sockopt))) {
1054+ return -EFAULT;
1055+ break;
1056+ }
1057+
1058+ spin_lock_bh(&ipt_acc_lock);
1059+ if (cmd == IPT_SO_GET_ACCOUNT_PREPARE_READ_FLUSH)
1060+ ret = ipt_acc_handle_prepare_read_flush(
1061+ handle.name, &dest, &handle.itemcount);
1062+ else
1063+ ret = ipt_acc_handle_prepare_read(
1064+ handle.name, &dest, &handle.itemcount);
1065+ spin_unlock_bh(&ipt_acc_lock);
1066+ // Error occured during prepare_read?
1067+ if (ret == -1)
1068+ return -EINVAL;
1069+
1070+ /* Allocate a userspace handle */
1071+ down(&ipt_acc_userspace_mutex);
1072+ if ((handle.handle_nr = ipt_acc_handle_find_slot()) == -1) {
1073+ ipt_acc_data_free(dest.data, dest.depth);
1074+ up(&ipt_acc_userspace_mutex);
1075+ return -EINVAL;
1076+ }
1077+ memcpy(&ipt_acc_handles[handle.handle_nr], &dest,
1078+ sizeof(struct ipt_acc_handle));
1079+ up(&ipt_acc_userspace_mutex);
1080+
1081+ if (copy_to_user(user, &handle,
1082+ sizeof(struct ipt_acc_handle_sockopt))) {
1083+ return -EFAULT;
1084+ break;
1085+ }
1086+ ret = 0;
1087+ break;
1088+ }
1089+ case IPT_SO_GET_ACCOUNT_GET_DATA:
1090+ if (*len < sizeof(struct ipt_acc_handle_sockopt)) {
e6915d4c 1091+ printk("ACCOUNT: ipt_acc_get_ctl: wrong data size (%u != %zu)"
52578af9 1092+ " for IPT_SO_GET_ACCOUNT_PREPARE_READ/READ_FLUSH\n",
1093+ *len, sizeof(struct ipt_acc_handle_sockopt));
1094+ break;
1095+ }
1096+
1097+ if (copy_from_user (&handle, user,
1098+ sizeof(struct ipt_acc_handle_sockopt))) {
1099+ return -EFAULT;
1100+ break;
1101+ }
1102+
1103+ if (handle.handle_nr >= ACCOUNT_MAX_HANDLES) {
1104+ return -EINVAL;
1105+ break;
1106+ }
1107+
1108+ if (*len < ipt_acc_handles[handle.handle_nr].itemcount
1109+ * sizeof(struct ipt_acc_handle_ip)) {
e6915d4c 1110+ printk("ACCOUNT: ipt_acc_get_ctl: not enough space (%u < %zu)"
52578af9 1111+ " to store data from IPT_SO_GET_ACCOUNT_GET_DATA\n",
1112+ *len, ipt_acc_handles[handle.handle_nr].itemcount
1113+ * sizeof(struct ipt_acc_handle_ip));
1114+ ret = -ENOMEM;
1115+ break;
1116+ }
1117+
1118+ down(&ipt_acc_userspace_mutex);
1119+ ret = ipt_acc_handle_get_data(handle.handle_nr, user);
1120+ up(&ipt_acc_userspace_mutex);
1121+ if (ret) {
1122+ printk("ACCOUNT: ipt_acc_get_ctl: ipt_acc_handle_get_data"
1123+ " failed for handle %u\n", handle.handle_nr);
1124+ break;
1125+ }
1126+
1127+ ret = 0;
1128+ break;
1129+ case IPT_SO_GET_ACCOUNT_GET_HANDLE_USAGE: {
1130+ unsigned int i;
1131+ if (*len < sizeof(struct ipt_acc_handle_sockopt)) {
e6915d4c 1132+ printk("ACCOUNT: ipt_acc_get_ctl: wrong data size (%u != %zu)"
52578af9 1133+ " for IPT_SO_GET_ACCOUNT_GET_HANDLE_USAGE\n",
1134+ *len, sizeof(struct ipt_acc_handle_sockopt));
1135+ break;
1136+ }
1137+
1138+ /* Find out how many handles are in use */
1139+ handle.itemcount = 0;
1140+ down(&ipt_acc_userspace_mutex);
1141+ for (i = 0; i < ACCOUNT_MAX_HANDLES; i++)
1142+ if (ipt_acc_handles[i].data)
1143+ handle.itemcount++;
1144+ up(&ipt_acc_userspace_mutex);
1145+
1146+ if (copy_to_user(user, &handle,
1147+ sizeof(struct ipt_acc_handle_sockopt))) {
1148+ return -EFAULT;
1149+ break;
1150+ }
1151+ ret = 0;
1152+ break;
1153+ }
1154+ case IPT_SO_GET_ACCOUNT_GET_TABLE_NAMES: {
1155+ u_int32_t size = 0, i, name_len;
1156+ char *tnames;
1157+
1158+ spin_lock_bh(&ipt_acc_lock);
1159+
1160+ /* Determine size of table names */
1161+ for (i = 0; i < ACCOUNT_MAX_TABLES; i++) {
1162+ if (ipt_acc_tables[i].name[0] != 0)
1163+ size += strlen (ipt_acc_tables[i].name) + 1;
1164+ }
1165+ size += 1; /* Terminating NULL character */
1166+
1167+ if (*len < size || size > PAGE_SIZE) {
1168+ spin_unlock_bh(&ipt_acc_lock);
1169+ printk("ACCOUNT: ipt_acc_get_ctl: not enough space (%u < %u < %lu)"
1170+ " to store table names\n", *len, size, PAGE_SIZE);
1171+ ret = -ENOMEM;
1172+ break;
1173+ }
1174+ /* Copy table names to userspace */
1175+ tnames = ipt_acc_tmpbuf;
1176+ for (i = 0; i < ACCOUNT_MAX_TABLES; i++) {
1177+ if (ipt_acc_tables[i].name[0] != 0) {
1178+ name_len = strlen (ipt_acc_tables[i].name) + 1;
1179+ memcpy(tnames, ipt_acc_tables[i].name, name_len);
1180+ tnames += name_len;
1181+ }
1182+ }
1183+ spin_unlock_bh(&ipt_acc_lock);
1184+
1185+ /* Terminating NULL character */
1186+ *tnames = 0;
1187+
1188+ /* Transfer to userspace */
1189+ if (copy_to_user(user, ipt_acc_tmpbuf, size))
1190+ return -EFAULT;
1191+
1192+ ret = 0;
1193+ break;
1194+ }
1195+ default:
1196+ printk("ACCOUNT: ipt_acc_get_ctl: unknown request %i\n", cmd);
1197+ }
1198+
1199+ return ret;
1200+}
1201+
1202+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
1203+static struct xt_target xt_acc_reg = {
1204+#else
1205+static struct ipt_target ipt_acc_reg = {
1206+#endif
1207+ .name = "ACCOUNT",
1208+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
1209+ .family = AF_INET,
1210+#endif
1211+ .target = ipt_acc_target,
1212+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
1213+ .targetsize = sizeof(struct ipt_acc_info),
1214+#endif
1215+ .checkentry = ipt_acc_checkentry,
1216+ .destroy = ipt_acc_destroy,
1217+ .me = THIS_MODULE
1218+};
1219+
1220+static struct nf_sockopt_ops ipt_acc_sockopts = {
1221+ .pf = PF_INET,
1222+ .set_optmin = IPT_SO_SET_ACCOUNT_HANDLE_FREE,
1223+ .set_optmax = IPT_SO_SET_ACCOUNT_MAX+1,
1224+ .set = ipt_acc_set_ctl,
1225+ .get_optmin = IPT_SO_GET_ACCOUNT_PREPARE_READ,
1226+ .get_optmax = IPT_SO_GET_ACCOUNT_MAX+1,
1227+ .get = ipt_acc_get_ctl
1228+};
1229+
1230+static int __init init(void)
1231+{
1232+ init_MUTEX(&ipt_acc_userspace_mutex);
1233+
1234+ if ((ipt_acc_tables =
1235+ kmalloc(ACCOUNT_MAX_TABLES *
1236+ sizeof(struct ipt_acc_table), GFP_KERNEL)) == NULL) {
1237+ printk("ACCOUNT: Out of memory allocating account_tables structure");
1238+ goto error_cleanup;
1239+ }
1240+ memset(ipt_acc_tables, 0,
1241+ ACCOUNT_MAX_TABLES * sizeof(struct ipt_acc_table));
1242+
1243+ if ((ipt_acc_handles =
1244+ kmalloc(ACCOUNT_MAX_HANDLES *
1245+ sizeof(struct ipt_acc_handle), GFP_KERNEL)) == NULL) {
1246+ printk("ACCOUNT: Out of memory allocating account_handles structure");
1247+ goto error_cleanup;
1248+ }
1249+ memset(ipt_acc_handles, 0,
1250+ ACCOUNT_MAX_HANDLES * sizeof(struct ipt_acc_handle));
1251+
1252+ /* Allocate one page as temporary storage */
1253+ if ((ipt_acc_tmpbuf = (void*)__get_free_page(GFP_KERNEL)) == NULL) {
1254+ printk("ACCOUNT: Out of memory for temporary buffer page\n");
1255+ goto error_cleanup;
1256+ }
1257+
1258+ /* Register setsockopt */
1259+ if (nf_register_sockopt(&ipt_acc_sockopts) < 0) {
1260+ printk("ACCOUNT: Can't register sockopts. Aborting\n");
1261+ goto error_cleanup;
1262+ }
1263+
1264+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
1265+ if (xt_register_target(&xt_acc_reg))
1266+#else
1267+ if (ipt_register_target(&ipt_acc_reg))
1268+#endif
1269+ goto error_cleanup;
1270+
1271+ return 0;
1272+
1273+error_cleanup:
1274+ if(ipt_acc_tables)
1275+ kfree(ipt_acc_tables);
1276+ if(ipt_acc_handles)
1277+ kfree(ipt_acc_handles);
1278+ if (ipt_acc_tmpbuf)
1279+ free_page((unsigned long)ipt_acc_tmpbuf);
1280+
1281+ return -EINVAL;
1282+}
1283+
1284+static void __exit fini(void)
1285+{
1286+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
1287+ xt_unregister_target(&xt_acc_reg);
1288+#else
1289+ ipt_unregister_target(&ipt_acc_reg);
1290+#endif
1291+
1292+ nf_unregister_sockopt(&ipt_acc_sockopts);
1293+
1294+ kfree(ipt_acc_tables);
1295+ kfree(ipt_acc_handles);
1296+ free_page((unsigned long)ipt_acc_tmpbuf);
1297+}
1298+
1299+module_init(init);
1300+module_exit(fini);
1301+MODULE_LICENSE("GPL");
e6915d4c 1302diff -uprN linux1/net/ipv4/netfilter/Kconfig.ladd linux-2.6/net/ipv4/netfilter/Kconfig.ladd
1303--- linux1/net/ipv4/netfilter/Kconfig 1970-01-01 01:00:00.000000000 +0100
1304+++ linux-2.6/net/ipv4/netfilter/Kconfig 2007-12-14 10:42:16.000000000 +0100
25914ba9 1305@@ -647,5 +647,26 @@
1306 If you want to compile it as a module, say M here and read
1307 <file:Documentation/modules.txt>. If unsure, say `N'.
1308
52578af9 1309+config IP_NF_TARGET_ACCOUNT
1310+ tristate "ACCOUNT target support"
1311+ depends on IP_NF_IPTABLES
1312+ ---help---
1313+ The ACCOUNT target is a high performance accounting system for local networks.
1314+ It takes two parameters: --addr network/netmask and --tname NAME.
1315+
1316+ --addr is the subnet which is accounted for
1317+ --tname is the table name where the information is stored
1318+
1319+ The data can be queried later using the libipt_ACCOUNT userspace library
1320+ or by the "iptaccount" tool which is part of the libipt_ACCOUNT package.
1321+
1322+ A special subnet is "0.0.0.0/0": All data is stored in the src_bytes
1323+ and src_packets structure of slot "0". This is useful if you want
1324+ to account the overall traffic to/from your internet provider.
1325+
1326+ For more information go to:
1327+ http://www.intra2net.com/de/produkte/opensource/ipt_account/
1328+
1329+ To compile it as a module, choose M here. If unsure, say N.
25914ba9 1330 endmenu
1331
e6915d4c 1332diff -uprN linux1/net/ipv4/netfilter/Makefile.ladd linux-2.6/net/ipv4/netfilter/Makefile.ladd
1333--- linux1/net/ipv4/netfilter/Makefile 1971-01-01 01:00:00.000000000 +0100
1334+++ linux-2.6/net/ipv4/netfilter/Makefile 2007-12-14 10:42:16.000000000 +0100
1335@@ -0,0 +0,1 @@
52578af9 1336+obj-$(CONFIG_IP_NF_TARGET_ACCOUNT) += ipt_ACCOUNT.o
1337diff -ur linux-2.6.19.1/include/linux/netfilter_ipv4/ip_tables.h linux-2.6.19.1.ipt_ACCOUNT/include/linux/netfilter_ipv4/ip_tables.h
1338--- linux-2.6.19.1/include/linux/netfilter_ipv4/ip_tables.h Mon Dec 11 20:32:53 2006
e6915d4c 1339+++ linux-2.6.19.1.ipt_ACCOUNT/include/linux/netfilter_ipv4/ip_tables.h Wed Dec 20 15:56:35 2006
52578af9 1340@@ -111,11 +111,22 @@
1341 #define IPT_SO_SET_ADD_COUNTERS (IPT_BASE_CTL + 1)
1342 #define IPT_SO_SET_MAX IPT_SO_SET_ADD_COUNTERS
1343
1344+#define IPT_SO_SET_ACCOUNT_HANDLE_FREE (IPT_BASE_CTL + 2)
1345+#define IPT_SO_SET_ACCOUNT_HANDLE_FREE_ALL (IPT_BASE_CTL + 3)
1346+#define IPT_SO_SET_ACCOUNT_MAX IPT_SO_SET_ACCOUNT_HANDLE_FREE_ALL
1347+
1348 #define IPT_SO_GET_INFO (IPT_BASE_CTL)
1349 #define IPT_SO_GET_ENTRIES (IPT_BASE_CTL + 1)
1350 #define IPT_SO_GET_REVISION_MATCH (IPT_BASE_CTL + 2)
1351 #define IPT_SO_GET_REVISION_TARGET (IPT_BASE_CTL + 3)
1352 #define IPT_SO_GET_MAX IPT_SO_GET_REVISION_TARGET
1353+
1354+#define IPT_SO_GET_ACCOUNT_PREPARE_READ (IPT_BASE_CTL + 4)
1355+#define IPT_SO_GET_ACCOUNT_PREPARE_READ_FLUSH (IPT_BASE_CTL + 5)
1356+#define IPT_SO_GET_ACCOUNT_GET_DATA (IPT_BASE_CTL + 6)
1357+#define IPT_SO_GET_ACCOUNT_GET_HANDLE_USAGE (IPT_BASE_CTL + 7)
1358+#define IPT_SO_GET_ACCOUNT_GET_TABLE_NAMES (IPT_BASE_CTL + 8)
1359+#define IPT_SO_GET_ACCOUNT_MAX IPT_SO_GET_ACCOUNT_GET_TABLE_NAMES
1360
1361 #define IPT_CONTINUE XT_CONTINUE
1362 #define IPT_RETURN XT_RETURN
This page took 0.213086 seconds and 4 git commands to generate.