1 diff -uNr linux-2.6.6/include.orig/linux/netfilter_ipv4/ipt_account.h linux-2.6.6/include/linux/netfilter_ipv4/ipt_account.h
2 --- linux-2.6.6/include.orig/linux/netfilter_ipv4/ipt_account.h 1970-01-01 01:00:00.000000000 +0100
3 +++ linux-2.6.6/include/linux/netfilter_ipv4/ipt_account.h 2004-05-22 15:29:38.813343664 +0200
6 + * accounting match (ipt_account.c)
7 + * (C) 2003,2004 by Piotr Gasid³o (quaker@barbara.eu.org)
11 + * This software is distributed under the terms of GNU GPL
14 +#ifndef _IPT_ACCOUNT_H_
15 +#define _IPT_ACCOUNT_H_
17 +#define IPT_ACCOUNT_NAME_LEN 64
19 +struct t_ipt_account_info {
20 + char name[IPT_ACCOUNT_NAME_LEN];
26 diff -uNr linux-2.6.6/net/ipv4/netfilter.orig/ipt_account.c linux-2.6.6/net/ipv4/netfilter/ipt_account.c
27 --- linux-2.6.6/net/ipv4/netfilter.orig/ipt_account.c 1970-01-01 01:00:00.000000000 +0100
28 +++ linux-2.6.6/net/ipv4/netfilter/ipt_account.c 2004-05-22 15:29:38.819342752 +0200
31 + * accounting match (ipt_account.c)
32 + * (C) 2003,2004 by Piotr Gasid³o (quaker@barbara.eu.org)
36 + * This software is distributed under the terms of GNU GPL
39 +#include <linux/module.h>
40 +#include <linux/skbuff.h>
41 +#include <linux/proc_fs.h>
42 +#include <linux/spinlock.h>
43 +#include <linux/vmalloc.h>
44 +#include <linux/interrupt.h>
46 +#include <asm/uaccess.h>
48 +#include <linux/ip.h>
49 +#include <linux/tcp.h>
50 +#include <linux/udp.h>
52 +#include <linux/netfilter_ipv4/ip_tables.h>
53 +#include <linux/netfilter_ipv4/ipt_account.h>
55 +static char version[] =
56 +KERN_INFO "ipt_account 0.1.5 : Piotr Gasid³o <quaker@barbara.eu.org>, http://www.barbara.eu.org/~quaker/ipt_account/\n";
58 +/* default rights for files created in /proc/net/ipt_account/ */
59 +static int ip_list_perms = 0644;
62 + * safe netmask, if you want account traffic for networks
63 + * bigger that /17 you must specify ip_list_max_hosts parameter
66 +static int ip_list_max_mask = 17;
67 +static int ip_list_max_hosts_count;
68 +static int debug = 0;
70 +/* module information */
71 +MODULE_AUTHOR("Piotr Gasid³o <quaker@barbara.eu.org>");
72 +MODULE_DESCRIPTION("Traffic accounting modules");
73 +MODULE_LICENSE("GPL");
74 +MODULE_PARM(ip_list_perms,"i");
75 +MODULE_PARM_DESC(ip_list_perms,"permissions on /proc/net/ipt_account/* files");
76 +MODULE_PARM(ip_list_max_mask, "i");
77 +MODULE_PARM_DESC(ip_list_max_mask, "maximum *save* size of one list (netmask)");
79 +MODULE_PARM(debug,"i");
80 +MODULE_PARM_DESC(debug,"debugging level, defaults to 0");
83 +/* structure with statistics counters */
84 +struct t_ipt_account_stat {
85 + u_int64_t b_all, b_tcp, b_udp, b_icmp, b_other; /* byte counters for all/tcp/udp/icmp/other traffic */
86 + u_int64_t p_all, p_tcp, p_udp, p_icmp, p_other; /* packet counters for all/tcp/udp/icmp/other traffic */
89 +/* structure holding to/from statistics for single ip */
90 +struct t_ipt_account_ip_list {
91 + struct t_ipt_account_stat src;
92 + struct t_ipt_account_stat dest;
95 +/* structure describing single table */
96 +struct t_ipt_account_table {
97 + char name[IPT_ACCOUNT_NAME_LEN]; /* table name ( = filename in /proc/net/ipt_account/) */
98 + struct t_ipt_account_ip_list *ip_list; /* table with statistics for each ip in network/netmask */
99 + struct t_ipt_account_table *next;
100 + u_int32_t network; /* network/netmask covered by table*/
102 + int use_count; /* rules counter - counting number of rules using this table */
103 + spinlock_t ip_list_lock;
104 + struct proc_dir_entry *status_proc_64, *status_proc_32;
107 +/* we must use spinlocks to avoid parallel modifications of table list */
108 +static spinlock_t ipt_account_tables_lock = SPIN_LOCK_UNLOCKED;
110 +static struct proc_dir_entry *proc_net_ipt_account = NULL;
112 +/* root pointer holding list of the tables */
113 +static struct t_ipt_account_table *ipt_account_tables = NULL;
115 +static int ip_list_read_proc_64(char *buffer, char **start, off_t offset,
116 + int length, int *eof, void *data) {
118 + int len = 0, last_len = 0;
119 + off_t pos = 0, begin = 0;
121 + u_int32_t address, index;
123 + struct t_ipt_account_table *table = (struct t_ipt_account_table*)data;
125 + spin_lock(&table->ip_list_lock);
126 + for (address = table->network; (u_int32_t)(address & table->netmask) == (u_int32_t)(table->network); address++) {
128 + index = address - table->network;
129 + len += sprintf(buffer + len,
130 + "ip = %u.%u.%u.%u bytes_src = %llu %llu %llu %llu %llu packets_src = %llu %llu %llu %llu %llu bytes_dest = %llu %llu %llu %llu %llu packets_dest = %llu %llu %llu %llu %llu\n",
132 + table->ip_list[index].src.b_all,
133 + table->ip_list[index].src.b_tcp,
134 + table->ip_list[index].src.b_udp,
135 + table->ip_list[index].src.b_icmp,
136 + table->ip_list[index].src.b_other,
138 + table->ip_list[index].src.p_all,
139 + table->ip_list[index].src.p_tcp,
140 + table->ip_list[index].src.p_udp,
141 + table->ip_list[index].src.p_icmp,
142 + table->ip_list[index].src.p_other,
144 + table->ip_list[index].dest.b_all,
145 + table->ip_list[index].dest.b_tcp,
146 + table->ip_list[index].dest.b_udp,
147 + table->ip_list[index].dest.b_icmp,
148 + table->ip_list[index].dest.b_other,
150 + table->ip_list[index].dest.p_all,
151 + table->ip_list[index].dest.p_tcp,
152 + table->ip_list[index].dest.p_udp,
153 + table->ip_list[index].dest.p_icmp,
154 + table->ip_list[index].dest.p_other
157 + if (pos < offset) {
161 + if (pos > offset + length) {
166 + spin_unlock(&table->ip_list_lock);
167 + *start = buffer + (offset - begin);
168 + len -= (offset - begin);
174 +static int ip_list_read_proc_32(char *buffer, char **start, off_t offset,
175 + int length, int *eof, void *data) {
177 + int len = 0, last_len = 0;
178 + off_t pos = 0, begin = 0;
180 + u_int32_t address, index;
182 + struct t_ipt_account_table *table = (struct t_ipt_account_table*)data;
184 + spin_lock(&table->ip_list_lock);
185 + for (address = table->network; (u_int32_t)(address & table->netmask) == (u_int32_t)(table->network); address++) {
187 + index = address - table->network;
188 + len += sprintf(buffer + len,
189 + "ip = %u.%u.%u.%u bytes_src = %u %u %u %u %u packets_src = %u %u %u %u %u bytes_dest = %u %u %u %u %u packets_dest = %u %u %u %u %u\n",
191 + (u_int32_t)table->ip_list[index].src.b_all,
192 + (u_int32_t)table->ip_list[index].src.b_tcp,
193 + (u_int32_t)table->ip_list[index].src.b_udp,
194 + (u_int32_t)table->ip_list[index].src.b_icmp,
195 + (u_int32_t)table->ip_list[index].src.b_other,
197 + (u_int32_t)table->ip_list[index].src.p_all,
198 + (u_int32_t)table->ip_list[index].src.p_tcp,
199 + (u_int32_t)table->ip_list[index].src.p_udp,
200 + (u_int32_t)table->ip_list[index].src.p_icmp,
201 + (u_int32_t)table->ip_list[index].src.p_other,
203 + (u_int32_t)table->ip_list[index].dest.b_all,
204 + (u_int32_t)table->ip_list[index].dest.b_tcp,
205 + (u_int32_t)table->ip_list[index].dest.b_udp,
206 + (u_int32_t)table->ip_list[index].dest.b_icmp,
207 + (u_int32_t)table->ip_list[index].dest.b_other,
209 + (u_int32_t)table->ip_list[index].dest.p_all,
210 + (u_int32_t)table->ip_list[index].dest.p_tcp,
211 + (u_int32_t)table->ip_list[index].dest.p_udp,
212 + (u_int32_t)table->ip_list[index].dest.p_icmp,
213 + (u_int32_t)table->ip_list[index].dest.p_other
217 + if (pos < offset) {
221 + if (pos > offset + length) {
226 + spin_unlock(&table->ip_list_lock);
227 + *start = buffer + (offset - begin);
228 + len -= (offset - begin);
234 +static int ip_list_write_proc(struct file *file, const char *buffer,
235 + unsigned long length, void *data) {
237 + int len = (length > 1024) ? length : 1024;
238 + struct t_ipt_account_table *table = (struct t_ipt_account_table*)data;
239 + char kernel_buffer[1024];
240 + u_int32_t hosts_count = INADDR_BROADCAST - table->netmask + 1;
242 + copy_from_user(kernel_buffer, buffer, len);
243 + kernel_buffer[len - 1] = 0;
245 + /* echo "reset" > /proc/net/ipt_recent/table clears the table */
246 + if (!strncmp(kernel_buffer, "reset", len)) {
247 + spin_lock(&table->ip_list_lock);
248 + memset(table->ip_list, 0, sizeof(struct t_ipt_account_ip_list) * hosts_count);
249 + spin_unlock(&table->ip_list_lock);
255 +/* do raw accounting */
256 +static void do_account(struct t_ipt_account_stat *stat, u_int8_t proto, u_int16_t pktlen) {
258 + /* update packet & bytes counters in *stat structure */
259 + stat->b_all += pktlen;
264 + stat->b_tcp += pktlen;
268 + stat->b_udp += pktlen;
272 + stat->b_icmp += pktlen;
276 + stat->b_other += pktlen;
281 +static int match(const struct sk_buff *skb,
282 + const struct net_device *in,
283 + const struct net_device *out,
284 + const void *matchinfo,
291 + const struct t_ipt_account_info *info = (struct t_ipt_account_info*)matchinfo;
292 + struct t_ipt_account_table *table;
300 + printk(KERN_INFO "ipt_account: match() entering.\n");
301 + printk(KERN_INFO "ipt_account: match() match name = %s.\n", info->name);
304 + spin_lock(&ipt_account_tables_lock);
305 + /* find the right table */
306 + table = ipt_account_tables;
307 + while (table && strncmp(table->name, info->name, IPT_ACCOUNT_NAME_LEN) && (table = table->next));
308 + spin_unlock(&ipt_account_tables_lock);
310 + if (table == NULL) {
311 + /* ups, no table with that name */
313 + printk(KERN_INFO "ipt_account: match() table %s not found. Leaving.\n", info->name);
318 + printk(KERN_INFO "ipt_account: match() table found %s\n", table->name);
320 + /* default: no match */
323 + /* get packet protocol/length */
325 + proto = skb->nh.iph->protocol;
328 + printk(KERN_INFO "ipt_account: match() got packet src = %u.%u.%u.%u, dst = %u.%u.%u.%u, proto = %u.\n",
329 + NIPQUAD(skb->nh.iph->saddr),
330 + NIPQUAD(skb->nh.iph->daddr),
334 + /* check whether traffic from source ip address ... */
335 + address = ntohl(skb->nh.iph->saddr);
337 + /* ... is being accounted by this table */
338 + if (address && ((u_int32_t)(address & table->netmask) == (u_int32_t)table->network)) {
340 + printk(KERN_INFO "ipt_account: match() accounting packet src = %u.%u.%u.%u, proto = %u.\n",
344 + /* yes, account this packet */
345 + spin_lock(&table->ip_list_lock);
346 + /* update counters this host */
347 + do_account(&table->ip_list[(u_int32_t)(address - table->network)].src, proto, pktlen);
348 + /* update counters for all hosts in this table (network address) */
349 + if (table->netmask != INADDR_BROADCAST)
350 + do_account(&table->ip_list[0].src, proto, pktlen);
351 + spin_unlock(&table->ip_list_lock);
352 + /* yes, it's a match */
356 + /* do the same thing with destination ip address */
357 + address = ntohl(skb->nh.iph->daddr);
358 + if (address && ((u_int32_t)(address & table->netmask) == (u_int32_t)table->network)) {
360 + printk(KERN_INFO "ipt_account: match() accounting packet dst = %u.%u.%u.%u, proto = %u.\n",
364 + spin_lock(&table->ip_list_lock);
365 + do_account(&table->ip_list[(u_int32_t)(address - table->network)].dest, proto, pktlen);
366 + if (table->netmask != INADDR_BROADCAST)
367 + do_account(&table->ip_list[0].dest, proto, pktlen);
368 + spin_unlock(&table->ip_list_lock);
374 + printk(KERN_INFO "ipt_account: match() leaving.\n");
380 +static int checkentry(const char *tablename,
381 + const struct ipt_ip *ip,
383 + unsigned int matchinfosize,
384 + unsigned int hook_mask)
386 + const struct t_ipt_account_info *info = matchinfo;
387 + struct t_ipt_account_table *table;
389 + char proc_entry_name[IPT_ACCOUNT_NAME_LEN + 3];
391 + u_int32_t hosts_count;
394 + printk(KERN_INFO "ipt_account: checkentry() entering.\n");
396 + if (matchinfosize != IPT_ALIGN(sizeof(struct t_ipt_account_info)))
399 + if (!info->name || !info->name[0])
402 + /* find whether table with this name already exists */
403 + spin_lock(&ipt_account_tables_lock);
404 + table = ipt_account_tables;
405 + while (table && strncmp(info->name, table->name, IPT_ACCOUNT_NAME_LEN) && (table = table->next));
408 + /* yes, table exists */
409 + if (info->network != table->network || info->netmask != table->netmask) {
411 + * tried to do accounting in existing table, but network/netmask in iptable rule
412 + * doesn't match network/netmask in table structure - deny adding the rule
414 + printk(KERN_ERR "ipt_account: checkentry() table %s found. But table netmask/network %u.%u.%u.%u/%u.%u.%u.%u differs from rule netmask/network %u.%u.%u.%u/%u.%u.%u.%u. Leaving without creating entry.\n",
416 + HIPQUAD(table->network),
417 + HIPQUAD(table->netmask),
418 + HIPQUAD(info->network),
419 + HIPQUAD(info->netmask)
421 + spin_unlock(&ipt_account_tables_lock);
425 + printk(KERN_INFO "ipt_account: checkentry() table %s found. Incrementing use count (use_count = %i). Leaving.\n", table->name, table->use_count);
426 + /* increase table use count */
427 + table->use_count++;
428 + spin_unlock(&ipt_account_tables_lock);
429 + /* everything went okey */
434 + printk(KERN_INFO "ipt_account: checkentry() table %s not found. Creating.\n", info->name);
436 + /* table doesn't exist - create one */
437 + table = vmalloc(sizeof(struct t_ipt_account_table));
438 + if (table == NULL) {
440 + printk(KERN_INFO "ipt_account: checkentry() unable to allocate memory (t_account_table) for table %s. Leaving.\n", info->name);
441 + spin_unlock(&ipt_account_tables_lock);
445 + /* set table parameters */
446 + strncpy(table->name, info->name, IPT_ACCOUNT_NAME_LEN);
447 + table->use_count = 1;
448 + table->network = info->network;
449 + table->netmask = info->netmask;
450 + table->ip_list_lock = SPIN_LOCK_UNLOCKED;
452 + hosts_count = INADDR_BROADCAST - table->netmask + 1;
455 + printk(KERN_INFO "ipt_account: checkentry() allocating memory for %u hosts (%u netmask).\n", hosts_count, info->netmask);
457 + /* check whether table is not too big */
458 + if (hosts_count > ip_list_max_hosts_count) {
459 + printk(KERN_ERR "ipt_account: checkentry() unable allocate memory for %u hosts (%u netmask). Increase value of ip_list_max_mask parameter.\n", hosts_count, info->netmask);
461 + spin_unlock(&ipt_account_tables_lock);
465 + table->ip_list = vmalloc(sizeof(struct t_ipt_account_ip_list) * hosts_count);
466 + if (table->ip_list == NULL) {
468 + printk(KERN_INFO "ipt_account: checkentry() unable to allocate memory (t_account_ip_list) for table %s. Leaving.\n", table->name);
470 + spin_unlock(&ipt_account_tables_lock);
474 + memset(table->ip_list, 0, sizeof(struct t_ipt_account_ip_list) * hosts_count);
477 + * create entries in /proc/net/ipt_account: one with full 64-bit counters and
478 + * second with 32-bit ones. The second can be used in programs supporting only 32-bit numbers
482 + strncpy(proc_entry_name, table->name, IPT_ACCOUNT_NAME_LEN);
483 + strncat(proc_entry_name, "_64", 4);
485 + table->status_proc_64 = create_proc_entry(proc_entry_name, ip_list_perms, proc_net_ipt_account);
486 + if (table->status_proc_64 == NULL) {
488 + printk(KERN_INFO "ipt_account: checkentry() unable to allocate memory (status_proc_64) for table %s. Leaving.\n", table->name);
489 + vfree(table->ip_list);
491 + spin_unlock(&ipt_account_tables_lock);
495 + table->status_proc_64->owner = THIS_MODULE;
496 + table->status_proc_64->read_proc = ip_list_read_proc_64;
497 + table->status_proc_64->write_proc = ip_list_write_proc;
498 + table->status_proc_64->data = table;
500 + strncpy(proc_entry_name, table->name, IPT_ACCOUNT_NAME_LEN);
501 + strncat(proc_entry_name, "_32", 4);
503 + table->status_proc_32 = create_proc_entry(proc_entry_name, ip_list_perms, proc_net_ipt_account);
504 + if (table->status_proc_32 == NULL) {
506 + printk(KERN_INFO "ipt_account: checkentry() unable to allocate memory (status_proc_32) for table %s. Leaving.\n", table->name);
507 + vfree(table->ip_list);
509 + spin_unlock(&ipt_account_tables_lock);
513 + table->status_proc_32->owner = THIS_MODULE;
514 + table->status_proc_32->read_proc = ip_list_read_proc_32;
515 + table->status_proc_32->write_proc = ip_list_write_proc;
516 + table->status_proc_32->data = table;
518 + /* finaly, insert table into list */
519 + table->next = ipt_account_tables;
520 + ipt_account_tables = table;
523 + printk(KERN_INFO "ipt_account: checkentry() successfully created table %s (use_count = %i).\n", table->name, table->use_count);
525 + spin_unlock(&ipt_account_tables_lock);
528 + printk(KERN_INFO "ipt_account: checkentry() leaving.\n");
532 +static void destroy(void *matchinfo,
533 + unsigned int matchinfosize)
535 + const struct t_ipt_account_info *info = matchinfo;
536 + struct t_ipt_account_table *table, *last_table;
537 + char proc_entry_name[IPT_ACCOUNT_NAME_LEN + 3];
540 + printk(KERN_INFO "ipt_account: destroy() entered.\n");
542 + if (matchinfosize != IPT_ALIGN(sizeof(struct t_ipt_account_info)))
545 + spin_lock(&ipt_account_tables_lock);
546 + table = ipt_account_tables;
548 + if (table == NULL) {
549 + /* list is empty, sometheing is realy wrong! */
551 + printk(KERN_INFO "ipt_account: destroy() unable to found any tables (asked for %s). Leaving.\n", info->name);
552 + spin_unlock(&ipt_account_tables_lock);
556 + /* find table combined with this rule - this code is taken for ipt_recent ;) */
558 + while (strncmp(table->name, info->name, IPT_ACCOUNT_NAME_LEN) && (last_table = table) && (table = table->next));
560 + if (table == NULL) {
561 + printk(KERN_ERR "ipt_account: destroy() unable to found table %s. Leaving.\n", info->name);
562 + spin_unlock(&ipt_account_tables_lock);
566 + /* decrease table use counter */
567 + table->use_count--;
568 + if (table->use_count != 0) {
569 + /* table is used by other rule, can't remove it */
571 + printk(KERN_INFO "ipt_account: destroy() table %s is still used (use_count = %i). Leaving.\n", table->name, table->use_count);
572 + spin_unlock(&ipt_account_tables_lock);
576 + /* table is not used by any other tule - remove it */
578 + printk(KERN_INFO "ipt_account: destroy() removing table %s (use_count = %i).\n", table->name, table->use_count);
581 + last_table->next = table->next;
583 + ipt_account_tables = table->next;
585 + spin_lock(&table->ip_list_lock);
586 + spin_unlock(&table->ip_list_lock);
588 + /* remove procfs entries */
589 + strncpy(proc_entry_name, table->name, IPT_ACCOUNT_NAME_LEN);
590 + strncat(proc_entry_name, "_64", 4);
591 + remove_proc_entry(proc_entry_name, proc_net_ipt_account);
592 + strncpy(proc_entry_name, table->name, IPT_ACCOUNT_NAME_LEN);
593 + strncat(proc_entry_name, "_32", 4);
594 + remove_proc_entry(proc_entry_name, proc_net_ipt_account);
595 + vfree(table->ip_list);
598 + spin_unlock(&ipt_account_tables_lock);
601 + printk(KERN_INFO "account: destroy() leaving.\n");
606 +static struct ipt_match account_match = {
615 +static int __init init(void)
619 + printk(KERN_INFO "account: __init(): ip_list_perms = %i, ip_list_max_mask = %i\n", ip_list_perms, ip_list_max_mask);
621 + if (ip_list_max_mask > 32 || ip_list_max_mask < 0) {
622 + printk(KERN_ERR "account: Wrong netmask given by ip_list_max_mask parameter (%u). Valid is 32 to 0.\n", ip_list_max_mask);
626 + ip_list_max_hosts_count = (1 << (32 - ip_list_max_mask)) + 1;
628 + /* create /proc/net/ipt_account directory */
629 + proc_net_ipt_account = proc_mkdir("ipt_account", proc_net);
630 + if (!proc_net_ipt_account)
633 + return ipt_register_match(&account_match);
636 +/* procedura usuwaj±ca modu³ */
637 +static void __exit fini(void)
639 + ipt_unregister_match(&account_match);
640 + /* remove /proc/net/ipt_account/ directory */
641 + remove_proc_entry("ipt_account", proc_net);
647 diff -uNr linux-2.6.6/net/ipv4/netfilter.orig/Kconfig linux-2.6.6/net/ipv4/netfilter/Kconfig
648 --- linux-2.6.6/net/ipv4/netfilter.orig/Kconfig 2004-05-22 15:21:26.033257624 +0200
649 +++ linux-2.6.6/net/ipv4/netfilter/Kconfig 2004-05-22 15:29:38.823342144 +0200
652 To compile it as a module, choose M here. If unsure, say N.
654 +config IP_NF_MATCH_ACCOUNT
655 + tristate "account match support"
656 + depends on IP_NF_IPTABLES
658 + This match is used for accounting traffic.
660 + Short options are available by using 'iptables -m account -h'
661 + Official Website: <http://www.barbara.eu.org/~quaker/ipt_account/>
663 + To compile it as a module, choose M here. If unsure, say N.
665 config IP_NF_MATCH_ECN
666 tristate "ECN match support"
667 depends on IP_NF_IPTABLES
668 diff -uNr linux-2.6.6/net/ipv4/netfilter.orig/Makefile linux-2.6.6/net/ipv4/netfilter/Makefile
669 --- linux-2.6.6/net/ipv4/netfilter.orig/Makefile 2004-05-22 15:21:26.034257472 +0200
670 +++ linux-2.6.6/net/ipv4/netfilter/Makefile 2004-05-22 15:30:30.150539224 +0200
672 obj-$(CONFIG_IP_NF_MATCH_FUZZY) += ipt_fuzzy.o
674 obj-$(CONFIG_IP_NF_MATCH_RECENT) += ipt_recent.o
675 +obj-$(CONFIG_IP_NF_MATCH_ACCOUNT) += ipt_account.o
677 obj-$(CONFIG_IP_NF_MATCH_ECN) += ipt_ecn.o
678 obj-$(CONFIG_IP_NF_MATCH_DSCP) += ipt_dscp.o