]> git.pld-linux.org Git - packages/kernel.git/blob - kernel-ipt_ACCOUNT.patch
- remove from HEAD
[packages/kernel.git] / kernel-ipt_ACCOUNT.patch
1 diff -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
4 @@ -0,0 +1,100 @@
5 +/***************************************************************************
6 + *   Copyright (C) 2004-2006 by Intra2net AG                               *
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*/
105 diff -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 @@
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 + *                                                                         * 
114 + *   Copyright (C) 2004-2007 by Intra2net AG                               *
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>
131 +#include <linux/semaphore.h>
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 +
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 +}
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
294 +                = ipt_acc_zalloc_page()) == NULL) {
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 +
311 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
312 +static bool ipt_acc_checkentry(const char *tablename,
313 +#else
314 +static int ipt_acc_checkentry(const char *tablename,
315 +#endif
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");
348 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
349 +        return false;
350 +#else
351 +        return 0;
352 +#endif
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 +
358 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
359 +    return true;
360 +#else
361 +    return 1;
362 +#endif
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] = 
508 +             ipt_acc_zalloc_page()) == NULL) {
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] 
524 +            = ipt_acc_zalloc_page()) == NULL) {
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] 
546 +            = ipt_acc_zalloc_page()) == NULL) {
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] 
562 +            = ipt_acc_zalloc_page()) == NULL) {
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 +
572 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
573 +static unsigned int ipt_acc_target(struct sk_buff *skb,
574 +#else
575 +static unsigned int ipt_acc_target(struct sk_buff **pskb,
576 +#endif
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;
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
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
606 +#endif
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 */
736 +    if ((dest->data = ipt_acc_zalloc_page()) == NULL) {
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] = 
758 +                     ipt_acc_zalloc_page()) == NULL) {
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] = 
780 +                     ipt_acc_zalloc_page()) == NULL) {
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] = 
796 +                             ipt_acc_zalloc_page()) == NULL) {
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 */
835 +    if (!(new_data_page = ipt_acc_zalloc_page())) {
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)) {
1000 +            printk("ACCOUNT: ipt_acc_set_ctl: wrong data size (%u != %zu) "
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)) {
1046 +                printk("ACCOUNT: ipt_acc_get_ctl: wrong data size (%u != %zu) "
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)) {
1091 +            printk("ACCOUNT: ipt_acc_get_ctl: wrong data size (%u != %zu)"
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)) {
1110 +            printk("ACCOUNT: ipt_acc_get_ctl: not enough space (%u < %zu)"
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)) {
1132 +                printk("ACCOUNT: ipt_acc_get_ctl: wrong data size (%u != %zu)"
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");
1302 diff -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
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  
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.
1330  endmenu
1331  
1332 diff -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 @@
1336 +obj-$(CONFIG_IP_NF_TARGET_ACCOUNT) += ipt_ACCOUNT.o
1337 diff -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
1339 +++ linux-2.6.19.1.ipt_ACCOUNT/include/linux/netfilter_ipv4/ip_tables.h Wed Dec 20 15:56:35 2006
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.143865 seconds and 3 git commands to generate.