~ubuntu-branches/ubuntu/lucid/xtables-addons/lucid

« back to all changes in this revision

Viewing changes to extensions/xt_ACCOUNT.c

  • Committer: Bazaar Package Importer
  • Author(s): Pierre Chifflier
  • Date: 2009-09-10 21:42:05 UTC
  • mfrom: (1.2.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20090910214205-neqgwq7y5nctaty7
Tags: 1.18-1
* New Upstream Version
  This version has support for 2.6.31 (Closes: #545542)
* Bump standards version (no changes)
* Depend on quilt (Closes: #533653)

Show diffs side-by-side

added added

removed removed

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