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