From 690f825ce237d43589e9e7b658af7258af47280b Mon Sep 17 00:00:00 2001 From: Augusto Bott Date: Fri, 6 Jan 2012 23:21:58 +0700 Subject: [PATCH] IPTraffic: K24 ipt_account module updated to v0.1.20 * iptables rules creation moved to the 'firewall' service (inside /etc/iptables on firewall.c) * merged the 'account service' into the firewall code (no sense to have a distinct/separate 'service') * http://code.google.com/p/ipt-account/ --- .../src/linux/linux/Documentation/Configure.help | 12 + release/src/linux/linux/config_base | 1 - .../include/linux/netfilter_ipv4/ipt_account.h | 50 +- .../src/linux/linux/net/ipv4/netfilter/Config.in | 3 - .../linux/linux/net/ipv4/netfilter/ipt_account.c | 1760 +++++++++----------- release/src/router/cstats/cstats.c | 5 + .../router/iptables/extensions/libipt_account.c | 649 ++++---- release/src/router/rc/Makefile | 1 - release/src/router/rc/account.c | 72 - release/src/router/rc/firewall.c | 41 +- release/src/router/rc/rc.h | 4 - release/src/router/rc/services.c | 24 +- 12 files changed, 1186 insertions(+), 1436 deletions(-) rewrite release/src/linux/linux/include/linux/netfilter_ipv4/ipt_account.h (69%) rewrite release/src/linux/linux/net/ipv4/netfilter/ipt_account.c (91%) rewrite release/src/router/iptables/extensions/libipt_account.c (80%) delete mode 100644 release/src/router/rc/account.c diff --git a/release/src/linux/linux/Documentation/Configure.help b/release/src/linux/linux/Documentation/Configure.help index a28ad007d7..3173feaf5b 100644 --- a/release/src/linux/linux/Documentation/Configure.help +++ b/release/src/linux/linux/Documentation/Configure.help @@ -2868,6 +2868,18 @@ CONFIG_IP_NF_IPTABLES If you want to compile it as a module, say M here and read . If unsure, say `N'. +account match support +CONFIG_IP_NF_MATCH_ACCOUNT + This match is used for gathering traffic statistics for particular + netblock. + + Short options are available by using 'iptables -m account -h' + Official Website: + Official Website: + + If you want to compile it as a module, say M here and read + Documentation/modules.txt. If unsure, say `N'. + recent match support CONFIG_IP_NF_MATCH_RECENT This match is used for creating one or many lists of recently diff --git a/release/src/linux/linux/config_base b/release/src/linux/linux/config_base index 2edbfdee0c..5c8b5a4d53 100644 --- a/release/src/linux/linux/config_base +++ b/release/src/linux/linux/config_base @@ -365,7 +365,6 @@ CONFIG_IP_NF_MATCH_CONDITION=m # CONFIG_IP_NF_MATCH_RANDOM is not set CONFIG_IP_NF_MATCH_RECENT=m CONFIG_IP_NF_MATCH_ACCOUNT=y -# CONFIG_IP_NF_MATCH_ACCOUNT_DEBUG is not set # CONFIG_IP_NF_POOL is not set # CONFIG_IP_NF_MATCH_ECN is not set CONFIG_IP_NF_MATCH_IPP2P=m diff --git a/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_account.h b/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_account.h dissimilarity index 69% index 6068d86d8b..e239c44e80 100644 --- a/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_account.h +++ b/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_account.h @@ -1,26 +1,24 @@ -/* - * accounting match (ipt_account.c) - * (C) 2003,2004 by Piotr Gasidlo (quaker@barbara.eu.org) - * - * Version: 0.1.7 - * - * This software is distributed under the terms of GNU GPL - */ - -#ifndef _IPT_ACCOUNT_H_ -#define _IPT_ACCOUNT_H_ - -#define IPT_ACCOUNT_NAME_LEN 64 - -#define IPT_ACCOUNT_NAME "ipt_account" -#define IPT_ACCOUNT_VERSION "0.1.7" - -struct t_ipt_account_info { - char name[IPT_ACCOUNT_NAME_LEN]; - u_int32_t network; - u_int32_t netmask; - int shortlisting:1; -}; - -#endif - +/* Copyright (c) 2004-2006 Piotr 'QuakeR' Gasidlo + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _IPT_ACCOUNT_H_ +#define _IPT_ACCOUNT_H_ + +#define IPT_ACCOUNT_NAME_LEN 64 + +struct t_ipt_account_table; + +struct t_ipt_account_info { + char name[IPT_ACCOUNT_NAME_LEN + 1]; + u_int32_t network, netmask; + int shortlisting:1; + /* pointer to the table for fast matching */ + struct t_ipt_account_table *table; +}; + +#endif /* _IPT_ACCOUNT_H */ + diff --git a/release/src/linux/linux/net/ipv4/netfilter/Config.in b/release/src/linux/linux/net/ipv4/netfilter/Config.in index 03ad8321fe..3218070756 100644 --- a/release/src/linux/linux/net/ipv4/netfilter/Config.in +++ b/release/src/linux/linux/net/ipv4/netfilter/Config.in @@ -44,9 +44,6 @@ if [ "$CONFIG_IP_NF_IPTABLES" != "n" ]; then dep_tristate ' random match support' CONFIG_IP_NF_MATCH_RANDOM $CONFIG_IP_NF_IPTABLES dep_tristate ' recent match support' CONFIG_IP_NF_MATCH_RECENT $CONFIG_IP_NF_IPTABLES dep_tristate ' account match support' CONFIG_IP_NF_MATCH_ACCOUNT $CONFIG_IP_NF_IPTABLES $CONFIG_PROC_FS - if [ "$CONFIG_IP_NF_MATCH_ACCOUNT" != "n" ]; then - bool ' account debugging output' CONFIG_IP_NF_MATCH_ACCOUNT_DEBUG - fi dep_tristate ' IP address pool support' CONFIG_IP_NF_POOL $CONFIG_IP_NF_IPTABLES if [ "$CONFIG_IP_NF_POOL" = "y" -o "$CONFIG_IP_NF_POOL" = "m" ]; then bool ' enable statistics on pool usage' CONFIG_IP_POOL_STATISTICS n diff --git a/release/src/linux/linux/net/ipv4/netfilter/ipt_account.c b/release/src/linux/linux/net/ipv4/netfilter/ipt_account.c dissimilarity index 91% index 7fd3456221..8b862588a3 100644 --- a/release/src/linux/linux/net/ipv4/netfilter/ipt_account.c +++ b/release/src/linux/linux/net/ipv4/netfilter/ipt_account.c @@ -1,942 +1,818 @@ -/* - * accounting match (ipt_account.c) - * (C) 2003,2004 by Piotr Gasidlo (quaker@barbara.eu.org) - * - * Version: 0.1.7 - * - * This software is distributed under the terms of GNU GPL - */ - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -#include -#include -#include - -#include -#include - -#if defined(CONFIG_IP_NF_MATCH_ACCOUNT_DEBUG) - #define dprintk(format,args...) printk(format,##args) -#else - #define dprintk(format,args...) -#endif - -static char version[] = -KERN_INFO IPT_ACCOUNT_NAME " " IPT_ACCOUNT_VERSION " : Piotr Gasid³o , http://www.barbara.eu.org/~quaker/ipt_account/\n"; - -/* rights for files created in /proc/net/ipt_account/ */ -static int permissions = 0644; -/* maximal netmask for single table */ -static int netmask = 16; - -/* module information */ -MODULE_AUTHOR("Piotr Gasidlo "); -MODULE_DESCRIPTION("Traffic accounting modules"); -MODULE_LICENSE("GPL"); -MODULE_PARM(permissions,"i"); -MODULE_PARM_DESC(permissions,"permissions on /proc/net/ipt_account/* files"); -MODULE_PARM(netmask, "i"); -MODULE_PARM_DESC(netmask, "maximum *save* size of one list (netmask)"); - -/* structure with statistics counters */ -struct t_ipt_account_stat { - u_int64_t b_all, b_tcp, b_udp, b_icmp, b_other; /* byte counters for all/tcp/udp/icmp/other traffic */ - u_int64_t p_all, p_tcp, p_udp, p_icmp, p_other; /* packet counters for all/tcp/udp/icmp/other traffic */ -}; - -/* stucture with statistics counters, used when table is created with --ashort switch */ -struct t_ipt_account_stat_short { - u_int64_t b_all; /* byte counters for all traffic */ - u_int64_t p_all; /* packet counters for all traffic */ -}; - -/* structure holding to/from statistics for single ip */ -struct t_ipt_account_ip_list { - struct t_ipt_account_stat src; - struct t_ipt_account_stat dest; - unsigned long time; /* time when this record was last updated */ - -}; - -/* same as above, for tables with --ashort switch */ -struct t_ipt_account_ip_list_short { - struct t_ipt_account_stat_short src; - struct t_ipt_account_stat_short dest; - unsigned long time; -}; - -/* structure describing single table */ -struct t_ipt_account_table { - char name[IPT_ACCOUNT_NAME_LEN]; /* table name ( = filename in /proc/net/ipt_account/) */ - union { /* table with statistics for each ip in network/netmask */ - struct t_ipt_account_ip_list *l; - struct t_ipt_account_ip_list_short *s; - } ip_list; - u_int32_t network; /* network/netmask covered by table*/ - u_int32_t netmask; - u_int32_t count; - int shortlisting:1; /* show only total columns of counters */ - int use_count; /* rules counter - counting number of rules using this table */ - struct t_ipt_account_table *next; - spinlock_t ip_list_lock; - struct proc_dir_entry *status_file; -}; - -/* we must use spinlocks to avoid parallel modifications of table list */ -static spinlock_t account_lock = SPIN_LOCK_UNLOCKED; - -static struct proc_dir_entry *proc_net_ipt_account = NULL; - -/* root pointer holding list of the tables */ -static struct t_ipt_account_table *account_tables = NULL; - -/* convert ascii to ip */ -int atoip(char *buffer, u_int32_t *ip) { - - char *bufferptr = buffer; - int part, shift; - - /* zero ip */ - *ip = 0; - - /* first must be a digit */ - if (!isdigit(*bufferptr)) - return 0; - - /* parse first 3 octets (III.III.III.iii) */ - for (part = 0, shift = 24; *bufferptr && shift; bufferptr++) { - if (isdigit(*bufferptr)) { - part = part * 10 + (*bufferptr - '0'); - continue; - } - if (*bufferptr == '.') { - if (part > 255) - return 0; - *ip |= part << shift; - shift -= 8; - part = 0; - continue; - } - return 0; - } - - /* we expect more digts */ - if (!*bufferptr) - return 0; - /* parse last octet (iii.iii.iii.III) */ - for (; *bufferptr; bufferptr++) { - if (isdigit(*bufferptr)) { - part = part * 10 + (*bufferptr - '0'); - continue; - } else { - if (part > 255) - return 0; - *ip |= part; - break; - } - } - return (bufferptr - buffer); -} - -/* convert ascii to 64bit integer */ -int atoi64(char *buffer, u_int64_t *i) { - char *bufferptr = buffer; - - /* zero integer */ - *i = 0; - - while (isdigit(*bufferptr)) { - *i = *i * 10 + (*bufferptr - '0'); - bufferptr++; - } - return (bufferptr - buffer); -} - -static void *account_seq_start(struct seq_file *s, loff_t *pos) -{ - struct proc_dir_entry *pde = s->private; - struct t_ipt_account_table *table = pde->data; - - unsigned int *bucket; - - spin_lock_bh(&table->ip_list_lock); - if (*pos >= table->count) - return NULL; - - bucket = kmalloc(sizeof(unsigned int), GFP_KERNEL); - if (!bucket) - return ERR_PTR(-ENOMEM); - *bucket = *pos; - return bucket; -} - -static void *account_seq_next(struct seq_file *s, void *v, loff_t *pos) -{ - struct proc_dir_entry *pde = s->private; - struct t_ipt_account_table *table = pde->data; - - unsigned int *bucket = (unsigned int *)v; - - *pos = ++(*bucket); - if (*pos >= table->count) { - kfree(v); - return NULL; - } - return bucket; -} - -static void account_seq_stop(struct seq_file *s, void *v) -{ - struct proc_dir_entry *pde = s->private; - struct t_ipt_account_table *table = pde->data; - unsigned int *bucket = (unsigned int *)v; - kfree(bucket); - spin_unlock_bh(&table->ip_list_lock); -} - -static int account_seq_write(struct file *file, const char *ubuffer, - size_t ulength, loff_t *pos) -{ - struct proc_dir_entry *pde = ((struct seq_file *)file->private_data)->private; - struct t_ipt_account_table *table = pde->data; - char buffer[1024], *bufferptr; - int length; - - u_int32_t ip; - int len, i; - struct t_ipt_account_ip_list l; - struct t_ipt_account_ip_list_short s; - u_int64_t *p, dummy; - - - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() entered.\n"); - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() ulength = %zi.\n", ulength); - - length = ulength; - if (ulength > 1024) - length = 1024; - if (copy_from_user(buffer, ubuffer, length)) - return -EFAULT; - buffer[length - 1] = 0; - bufferptr = buffer; - - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() buffer = \'%s\' length = %i.\n", buffer, length); - - /* reset table counters */ - if (!memcmp(buffer, "reset", 5)) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got \"reset\".\n"); - if (!table->shortlisting) { - spin_lock_bh(&table->ip_list_lock); - memset(table->ip_list.l, 0, sizeof(struct t_ipt_account_ip_list) * table->count); - spin_unlock_bh(&table->ip_list_lock); - } else { - spin_lock_bh(&table->ip_list_lock); - memset(table->ip_list.s, 0, sizeof(struct t_ipt_account_ip_list_short) * table->count); - spin_unlock_bh(&table->ip_list_lock); - } - return length; - } - - if (!memcmp(buffer, "ip", 2)) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got \"ip\".\n"); - bufferptr += 2; - if (!isspace(*bufferptr)) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected space (%ti).\n", bufferptr - buffer); - return length; /* expected space */ - } - bufferptr += 1; - if (*bufferptr != '=') { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected equal (%ti).\n", bufferptr - buffer); - return length; /* expected equal */ - } - bufferptr += 1; - if (!isspace(*bufferptr)) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected space (%ti).\n", bufferptr - buffer); - return length; /* expected space */ - } - bufferptr += 1; - if (!(len = atoip(bufferptr, &ip))) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected ip (%ti).\n", bufferptr - buffer); - return length; /* expected ip */ - } - bufferptr += len; - if ((ip & table->netmask) != table->network) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected ip [%u.%u.%u.%u] from table's network/netmask [%u.%u.%u.%u/%u.%u.%u.%u].\n", HIPQUAD(ip), HIPQUAD(table->network), HIPQUAD(table->netmask)); - return length; /* expected ip from table's network/netmask */ - } - if (!table->shortlisting) { - memset(&l, 0, sizeof(struct t_ipt_account_ip_list)); - while(*bufferptr) { - if (!isspace(*bufferptr)) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected space (%ti).\n", bufferptr - buffer); - return length; /* expected space */ - } - bufferptr += 1; - if (!memcmp(bufferptr, "bytes_src", 9)) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got bytes_src (%ti).\n", bufferptr - buffer); - p = &l.src.b_all; - bufferptr += 9; - } else if (!memcmp(bufferptr, "bytes_dest", 10)) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got bytes_dest (%ti).\n", bufferptr - buffer); - p = &l.dest.b_all; - bufferptr += 10; - } else if (!memcmp(bufferptr, "packets_src", 11)) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got packets_src (%ti).\n", bufferptr - buffer); - p = &l.src.p_all; - bufferptr += 11; - } else if (!memcmp(bufferptr, "packets_dest", 12)) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got packets_dest (%ti).\n", bufferptr - buffer); - p = &l.dest.p_all; - bufferptr += 12; - } else if (!memcmp(bufferptr, "time", 4)) { - /* time hack, ignore time tokens */ - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got time (%ti).\n", bufferptr - buffer); - bufferptr += 4; - if (!isspace(*bufferptr)) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected space (%ti).\n", bufferptr - buffer); - return length; /* expected space */ - } - bufferptr += 1; - if (*bufferptr != '=') { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected equal (%ti).\n", bufferptr - buffer); - return length; /* expected equal */ - } - bufferptr += 1; - if (!isspace(*bufferptr)) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected space (%ti).\n", bufferptr - buffer); - return length; /* expected space */ - } - bufferptr += 1; - if (!(len = atoi64(bufferptr, &dummy))) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected int64 (%ti).\n", bufferptr - buffer); - return length; /* expected int64 */ - } - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got %llu (%ti).\n", dummy, bufferptr - buffer); - bufferptr += len; - continue; /* skip time token */ - } else - return length; /* expected token */ - if (!isspace(*bufferptr)) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected space (%ti).\n", bufferptr - buffer); - return length; /* expected space */ - } - bufferptr += 1; - if (*bufferptr != '=') { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected equal (%ti).\n", bufferptr - buffer); - return length; /* expected equal */ - } - bufferptr += 1; - for (i = 0; i < 5; i++) { - if (!isspace(*bufferptr)) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected space (%ti).\n", bufferptr - buffer); - return length; /* expected space */ - } - bufferptr += 1; - if (!(len = atoi64(bufferptr, p))) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected int64 (%ti).\n", bufferptr - buffer); - return length; /* expected int64 */ - } - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got %llu (%ti).\n", *p, bufferptr - buffer); - bufferptr += len; - p++; - } - } - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() updating row.\n"); - spin_lock_bh(&table->ip_list_lock); - /* update counters, do not overwrite time field */ - memcpy(&table->ip_list.l[ip - table->network], &l, sizeof(struct t_ipt_account_ip_list) - sizeof(unsigned long)); - spin_unlock_bh(&table->ip_list_lock); - } else { - memset(&s, 0, sizeof(struct t_ipt_account_ip_list_short)); - while(*bufferptr) { - if (!isspace(*bufferptr)) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected space (%ti).\n", bufferptr - buffer); - return length; /* expected space */ - } - bufferptr += 1; - if (!memcmp(bufferptr, "bytes_src", 9)) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got bytes_src (%ti).\n", bufferptr - buffer); - p = &s.src.b_all; - bufferptr += 9; - } else if (!memcmp(bufferptr, "bytes_dest", 10)) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got bytes_dest (%ti).\n", bufferptr - buffer); - p = &s.dest.b_all; - bufferptr += 10; - } else if (!memcmp(bufferptr, "packets_src", 11)) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got packets_src (%ti).\n", bufferptr - buffer); - p = &s.src.p_all; - bufferptr += 11; - } else if (!memcmp(bufferptr, "packets_dest", 12)) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got packets_dest (%ti).\n", bufferptr - buffer); - p = &s.dest.p_all; - bufferptr += 12; - } else if (!memcmp(bufferptr, "time", 4)) { - /* time hack, ignore time tokens */ - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got time (%ti).\n", bufferptr - buffer); - bufferptr += 4; - if (!isspace(*bufferptr)) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected space (%ti).\n", bufferptr - buffer); - return length; /* expected space */ - } - bufferptr += 1; - if (*bufferptr != '=') { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected equal (%ti).\n", bufferptr - buffer); - return length; /* expected equal */ - } - bufferptr += 1; - if (!isspace(*bufferptr)) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected space (%ti).\n", bufferptr - buffer); - return length; /* expected space */ - } - bufferptr += 1; - if (!(len = atoi64(bufferptr, &dummy))) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected int64 (%ti).\n", bufferptr - buffer); - return length; /* expected int64 */ - } - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got %llu (%ti).\n", dummy, bufferptr - buffer); - bufferptr += len; - continue; /* skip time token */ - } else { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected token (%ti).\n", bufferptr - buffer); - return length; /* expected token */ - } - if (!isspace(*bufferptr)) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected space (%ti).\n", bufferptr - buffer); - return length; /* expected space */ - } - bufferptr += 1; - if (*bufferptr != '=') { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected equal (%ti).\n", bufferptr - buffer); - return length; /* expected equal */ - } - bufferptr += 1; - if (!isspace(*bufferptr)) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected space (%ti).\n", bufferptr - buffer); - return length; /* expected space */ - } - bufferptr += 1; - if (!(len = atoi64(bufferptr, p))) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected int64 (%ti).\n", bufferptr - buffer); - return length; /* expected int64 */ - } - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got %llu (%ti).\n", *p, bufferptr - buffer); - bufferptr += len; - } - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() updating row.\n"); - spin_lock_bh(&table->ip_list_lock); - /* update counters, do not overwrite time field */ - memcpy(&table->ip_list.s[ip - table->network], &s, sizeof(struct t_ipt_account_ip_list_short) - sizeof(unsigned long)); - spin_unlock_bh(&table->ip_list_lock); - } - } - - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() left.\n"); - return length; -} - - -static int account_seq_show(struct seq_file *s, void *v) -{ - struct proc_dir_entry *pde = s->private; - struct t_ipt_account_table *table = pde->data; - unsigned int *bucket = (unsigned int *)v; - - u_int32_t address = table->network + *bucket; - struct timespec last; - - if (!table->shortlisting) { - jiffies_to_timespec(jiffies - table->ip_list.l[*bucket].time, &last); - seq_printf(s, - "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 time = %lu\n", - HIPQUAD(address), - table->ip_list.l[*bucket].src.b_all, - table->ip_list.l[*bucket].src.b_tcp, - table->ip_list.l[*bucket].src.b_udp, - table->ip_list.l[*bucket].src.b_icmp, - table->ip_list.l[*bucket].src.b_other, - table->ip_list.l[*bucket].src.p_all, - table->ip_list.l[*bucket].src.p_tcp, - table->ip_list.l[*bucket].src.p_udp, - table->ip_list.l[*bucket].src.p_icmp, - table->ip_list.l[*bucket].src.p_other, - table->ip_list.l[*bucket].dest.b_all, - table->ip_list.l[*bucket].dest.b_tcp, - table->ip_list.l[*bucket].dest.b_udp, - table->ip_list.l[*bucket].dest.b_icmp, - table->ip_list.l[*bucket].dest.b_other, - table->ip_list.l[*bucket].dest.p_all, - table->ip_list.l[*bucket].dest.p_tcp, - table->ip_list.l[*bucket].dest.p_udp, - table->ip_list.l[*bucket].dest.p_icmp, - table->ip_list.l[*bucket].dest.p_other, - last.tv_sec - ); - } else { - jiffies_to_timespec(jiffies - table->ip_list.s[*bucket].time, &last); - seq_printf(s, - "ip = %u.%u.%u.%u bytes_src = %llu packets_src = %llu bytes_dest = %llu packets_dest = %llu time = %lu\n", - HIPQUAD(address), - table->ip_list.s[*bucket].src.b_all, - table->ip_list.s[*bucket].src.p_all, - table->ip_list.s[*bucket].dest.b_all, - table->ip_list.s[*bucket].dest.p_all, - last.tv_sec - ); - } - return 0; -} - -static struct seq_operations account_seq_ops = { - .start = account_seq_start, - .next = account_seq_next, - .stop = account_seq_stop, - .show = account_seq_show -}; - -static int account_seq_open(struct inode *inode, struct file *file) -{ - int ret = seq_open(file, &account_seq_ops); - - if (!ret) { - struct seq_file *sf = file->private_data; - sf->private = PDE(inode); - } - return ret; -} - -static struct file_operations account_file_ops = { - .owner = THIS_MODULE, - .open = account_seq_open, - .read = seq_read, - .write = account_seq_write, - .llseek = seq_lseek, - .release = seq_release -}; - -/* do raw accounting */ -static inline void do_account(struct t_ipt_account_stat *stat, const struct sk_buff *skb) { - - /* update packet & bytes counters in *stat structure */ - stat->b_all += skb->len; - stat->p_all++; - - switch (skb->nh.iph->protocol) { - case IPPROTO_TCP: - stat->b_tcp += skb->len; - stat->p_tcp++; - break; - case IPPROTO_UDP: - stat->b_udp += skb->len; - stat->p_udp++; - break; - case IPPROTO_ICMP: - stat->b_icmp += skb->len; - stat->p_icmp++; - break; - default: - stat->b_other += skb->len; - stat->p_other++; - } -} - -static inline void do_account_short(struct t_ipt_account_stat_short *stat, const struct sk_buff *skb) { - - /* update packet & bytes counters in *stat structure */ - stat->b_all += skb->len; - stat->p_all++; -} - -static int match(const struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - const void *matchinfo, - int offset, - const void *hdr, - u_int16_t datalen, - int *hotdrop) -{ - - const struct t_ipt_account_info *info = (struct t_ipt_account_info*)matchinfo; - struct t_ipt_account_table *table; - int ret; - unsigned long now; - - u_int32_t address; - - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": match() entered.\n"); - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": match() match name = %s.\n", info->name); - - spin_lock_bh(&account_lock); - /* find the right table */ - table = account_tables; - while (table && strncmp(table->name, info->name, IPT_ACCOUNT_NAME_LEN) && (table = table->next)); - spin_unlock_bh(&account_lock); - - if (table == NULL) { - /* ups, no table with that name */ - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": match() table %s not found. Leaving.\n", info->name); - return 0; - } - - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": match() table found %s\n", table->name); - - /* lock table while updating statistics */ - spin_lock_bh(&table->ip_list_lock); - - /* default: no match */ - ret = 0; - - /* get current time */ - now = jiffies; - - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": match() got packet src = %u.%u.%u.%u, dst = %u.%u.%u.%u, proto = %u.\n", NIPQUAD(skb->nh.iph->saddr), NIPQUAD(skb->nh.iph->daddr), skb->nh.iph->protocol); - - /* check whether traffic from source ip address ... */ - address = ntohl(skb->nh.iph->saddr); - /* ... is being accounted by this table */ - if (address && ((u_int32_t)(address & table->netmask) == (u_int32_t)table->network)) { - /* yes, account this packet */ - dprintk(KERN_INFO "ipt_account: match() accounting packet src = %u.%u.%u.%u, proto = %u.\n", HIPQUAD(address), skb->nh.iph->protocol); - /* update counters this host */ - if (!table->shortlisting) { - do_account(&table->ip_list.l[address - table->network].src, skb); - table->ip_list.l[address - table->network].time = now; - /* update also counters for all hosts in this table (network address) */ - if (table->netmask != INADDR_BROADCAST) { - do_account(&table->ip_list.l[0].src, skb); - table->ip_list.l[0].time = now; - } - } else { - do_account_short(&table->ip_list.s[address - table->network].src, skb); - table->ip_list.s[address - table->network].time = now; - /* update also counters for all hosts in this table (network address) */ - if (table->netmask != INADDR_BROADCAST) { - do_account_short(&table->ip_list.s[0].src, skb); - table->ip_list.s[0].time = now; - } - } - /* yes, it's a match */ - ret = 1; - } - - /* do the same thing with destination ip address */ - address = ntohl(skb->nh.iph->daddr); - if (address && ((u_int32_t)(address & table->netmask) == (u_int32_t)table->network)) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": match() accounting packet dst = %u.%u.%u.%u, proto = %u.\n", HIPQUAD(address), skb->nh.iph->protocol); - if (!table->shortlisting) { - do_account(&table->ip_list.l[address - table->network].dest, skb); - table->ip_list.l[address - table->network].time = now; - if (table->netmask != INADDR_BROADCAST) { - do_account(&table->ip_list.l[0].dest, skb); - table->ip_list.s[0].time = now; - } - } else { - do_account_short(&table->ip_list.s[address - table->network].dest, skb); - table->ip_list.s[address - table->network].time = now; - if (table->netmask != INADDR_BROADCAST) { - do_account_short(&table->ip_list.s[0].dest, skb); - table->ip_list.s[0].time = now; - } - } - ret = 1; - } - spin_unlock_bh(&table->ip_list_lock); - - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": match() left.\n"); - - return ret; -} - -static int checkentry(const char *tablename, - const struct ipt_ip *ip, - void *matchinfo, - unsigned int matchinfosize, - unsigned int hook_mask) -{ - const struct t_ipt_account_info *info = matchinfo; - struct t_ipt_account_table *table, *find_table, *last_table; - int ret = 0; - - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() entered.\n"); - - if (matchinfosize != IPT_ALIGN(sizeof(struct t_ipt_account_info))) return 0; - if (!info->name || !info->name[0]) return 0; - - /* find whether table with this name already exists */ - spin_lock_bh(&account_lock); - find_table = account_tables; - while( (last_table = find_table) && strncmp(info->name,find_table->name,IPT_ACCOUNT_NAME_LEN) && (find_table = find_table->next) ); - if (find_table != NULL) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() table %s found.\n", info->name); - /* if table exists, check whether table network/netmask equals rule network/netmask */ - if (find_table->network != info->network || find_table->netmask != info->netmask || find_table->shortlisting != info->shortlisting) { - spin_unlock_bh(&account_lock); - printk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() wrong parameters (not equals existing table parameters).\n"); - ret = 0; - goto failure; - } - /* increment table use count */ - find_table->use_count++; - spin_unlock_bh(&account_lock); - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() incrementing use count.\n"); - ret = 1; - goto failure; - } - spin_unlock_bh(&account_lock); - - /* check netmask first, before allocating memory */ - if (info->netmask < ((1 << netmask) - 1)) { - printk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() too big netmask.\n"); - ret = 0; - goto failure; - } - - /* table doesn't exist - create new */ - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() allocating %zu for new table %s.\n", sizeof(struct t_ipt_account_table), info->name); - table = vmalloc(sizeof(struct t_ipt_account_table)); - if (table == NULL) { - printk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() failed to allocate %zu for new table %s.\n", sizeof(struct t_ipt_account_table), info->name); - ret = 0; /* was -ENOMEM */ - goto failure; - } - - /* setup table parameters */ - table->ip_list_lock = SPIN_LOCK_UNLOCKED; - table->next = NULL; - table->use_count = 1; - table->network = info->network; - table->netmask = info->netmask; - table->shortlisting = info->shortlisting; - table->count = (~table->netmask) + 1; - strncpy(table->name,info->name,IPT_ACCOUNT_NAME_LEN); - table->name[IPT_ACCOUNT_NAME_LEN - 1] = '\0'; - - /* allocate memory for table->ip_list */ - if (!table->shortlisting) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() allocating %zu for ip_list.\n", sizeof(struct t_ipt_account_ip_list) * table->count); - table->ip_list.l = vmalloc(sizeof(struct t_ipt_account_ip_list) * table->count); - if (table->ip_list.l == NULL) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() failed to allocate %zu for ip_list.\n", sizeof(struct t_ipt_account_ip_list) * table->count); - ret = 0; /* was -ENOMEM */ - goto failure_table; - } - memset(table->ip_list.l, 0, sizeof(struct t_ipt_account_ip_list) * table->count); - } else { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() allocating %zu for ip_list.\n", sizeof(struct t_ipt_account_ip_list_short) * table->count); - table->ip_list.s = vmalloc(sizeof(struct t_ipt_account_ip_list_short) * table->count); - if (table->ip_list.s == NULL) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() failed to allocate %zu for ip_list.\n", sizeof(struct t_ipt_account_ip_list_short) * table->count); - ret = 0; /* was -ENOMEM */ - goto failure_table; - } - memset(table->ip_list.s, 0, sizeof(struct t_ipt_account_ip_list_short) * table->count); - } - - /* put table into chain */ - spin_lock_bh(&account_lock); - find_table = account_tables; - while( (last_table = find_table) && strncmp(info->name, find_table->name, IPT_ACCOUNT_NAME_LEN) && (find_table = find_table->next) ); - if (find_table != NULL) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() table %s found.\n", info->name); - if (find_table->network != info->network || find_table->netmask != info->netmask) { - spin_unlock_bh(&account_lock); - printk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() wrong network/netmask.\n"); - ret = 0; - goto failure_ip_list; - } - find_table->use_count++; - spin_unlock_bh(&account_lock); - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() incrementing use count.\n"); - ret = 1; - goto failure_ip_list; - } - if (!last_table) - account_tables = table; - else - last_table->next = table; - spin_unlock_bh(&account_lock); - - /* create procfs status file */ - table->status_file = create_proc_entry(table->name, permissions, proc_net_ipt_account); - if (table->status_file == NULL) { - ret = 0; /* was -ENOMEM */ - goto failure_unlink; - } - table->status_file->owner = THIS_MODULE; - table->status_file->data = table; - wmb(); -// if (!table->shortlisting) - table->status_file->proc_fops = &account_file_ops; -// else -// table->status_file->proc_fops = &account_file_ops_short; - - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() left.\n"); - /* everything went just okey */ - return 1; - - /* do cleanup in case of failure */ -failure_unlink: - /* remove table from list */ - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() removing table.\n"); - spin_lock_bh(&account_lock); - last_table = NULL; - table = account_tables; - if (table == NULL) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() no table found. Leaving.\n"); - spin_unlock_bh(&account_lock); - return 0; /* was -ENOMEM */ - } - while (strncmp(info->name, table->name, IPT_ACCOUNT_NAME_LEN) && (last_table = table) && (table = table->next)); - if (table == NULL) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() table already destroyed. Leaving.\n"); - spin_unlock_bh(&account_lock); - return 0; /* was -ENOMEM */ - } - if (last_table) - last_table->next = table->next; - else - account_tables = table->next; - spin_unlock_bh(&account_lock); -failure_ip_list: - /* free memory allocated for statistics table */ - if (!table->shortlisting) - vfree(table->ip_list.l); - else - vfree(table->ip_list.s); -failure_table: - /* free table */ - vfree(table); -failure: - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() left. Table not created.\n"); - /* failure return */ - return ret; -} - -static void destroy(void *matchinfo, - unsigned int matchinfosize) -{ - const struct t_ipt_account_info *info = matchinfo; - struct t_ipt_account_table *table, *last_table; - - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": destory() entered.\n"); - - if (matchinfosize != IPT_ALIGN(sizeof(struct t_ipt_account_info))) return; - - /* search for table */ - spin_lock_bh(&account_lock); - last_table = NULL; - table = account_tables; - if(table == NULL) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": destory() no tables found. Leaving.\n"); - spin_unlock_bh(&account_lock); - return; - } - while( strncmp(info->name,table->name,IPT_ACCOUNT_NAME_LEN) && (last_table = table) && (table = table->next) ); - if (table == NULL) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": destory() no table %s not found. Leaving.\n", info->name); - spin_unlock_bh(&account_lock); - return; - } - - /* decrement table use-count */ - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": destory() decrementing use count.\n"); - table->use_count--; - if (table->use_count) { - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": destory() table still in use. Leaving.\n"); - spin_unlock_bh(&account_lock); - return; - } - - /* remove table if use-count is zero */ - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": destory() table %s not used. Removing.\n", table->name); - - /* unlink table */ - if(last_table) - last_table->next = table->next; - else - account_tables = table->next; - spin_unlock_bh(&account_lock); - - /* wait while table is still in use */ - spin_lock_bh(&table->ip_list_lock); - spin_unlock_bh(&table->ip_list_lock); - - /* remove proc entries */ - remove_proc_entry(table->name, proc_net_ipt_account); - - /* remove table */ - if (!table->shortlisting) - vfree(table->ip_list.l); - else - vfree(table->ip_list.s); - vfree(table); - - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": destory() left.\n"); - return; -} - -static struct ipt_match account_match = { - .name = "account", - .match = &match, - .checkentry = &checkentry, - .destroy = &destroy, - .me = THIS_MODULE -}; - -static int __init init(void) -{ - int err; - - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": __init() entered.\n"); - printk(version); - /* check params */ - if (netmask > 32 || netmask < 0) { - printk(KERN_INFO "account: Wrong netmask given by netmask parameter (%i). Valid is 32 to 0.\n", netmask); - err = -EINVAL; - goto doexit; - } - - /* create /proc/net/ipt_account directory */ - proc_net_ipt_account = proc_mkdir("ipt_account", proc_net); - if (!proc_net_ipt_account) { - printk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() failed to create procfs entry.\n"); - err = -ENOMEM; - goto doexit; - } - proc_net_ipt_account->owner = THIS_MODULE; - - err = ipt_register_match(&account_match); - if (err) { - printk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() failed to register match.\n"); - remove_proc_entry("ipt_account", proc_net); - } -doexit: - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": __init() left.\n"); - return err; -} - -static void __exit fini(void) -{ - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": __exit() entered.\n"); - - ipt_unregister_match(&account_match); - /* remove /proc/net/ipt_account/ directory */ - remove_proc_entry("ipt_account", proc_net); - - dprintk(KERN_INFO IPT_ACCOUNT_NAME ": __exit() left.\n"); -} - -module_init(init); -module_exit(fini); - +/* Copyright (c) 2004-2006 Piotr 'QuakeR' Gasidlo + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +// #include +#include +#include +#include +#include +#include +#include +#include +#include + +#define IPT_ACCOUNT_VERSION "0.1.20" + +// #define DEBUG_IPT_ACCOUNT + +MODULE_AUTHOR("Piotr Gasidlo "); +MODULE_DESCRIPTION("Traffic accounting module"); +MODULE_LICENSE("GPL"); + +#include +#include + +/* defaults, can be overriden */ +static unsigned int netmask = 16; /* Safe netmask, if you try to create table + for larger netblock you will get error. + Increase by command line only when you + known what are you doing. */ + +#ifdef DEBUG_IPT_ACCOUNT +static int debug = 0; +#endif + +MODULE_PARM(netmask, "i"); +MODULE_PARM_DESC(netmask,"maximum *save* netmask"); +#ifdef DEBUG_IPT_ACCOUNT +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug,"enable debugging output"); +#endif + +/* structure with statistics counter, used when table is created without --ashort switch */ +struct t_ipt_account_stat_long { + u_int64_t b_all, b_tcp, b_udp, b_icmp, b_other; + u_int64_t p_all, p_tcp, p_udp, p_icmp, p_other; +}; + +/* same as above, for tables created with --ashort switch */ +struct t_ipt_account_stat_short { + u_int64_t b_all; + u_int64_t p_all; +}; + +/* structure holding to/from statistics for single ip when table is created without --ashort switch */ +struct t_ipt_account_stats_long { + struct t_ipt_account_stat_long src, dst; + struct timespec time; /* time, when statistics was last modified */ +}; + +/* same as above, for tables created with --ashort switch */ +struct t_ipt_account_stats_short { + struct t_ipt_account_stat_short src, dst; + struct timespec time; +}; + +/* structure describing single table */ +struct t_ipt_account_table { + struct list_head list; + atomic_t use; /* use counter, the number of rules which points to this table */ + + char name[IPT_ACCOUNT_NAME_LEN + 1]; /* table name ( = filename in /proc/net/ipt_account/) */ + u_int32_t network, netmask, count; /* network/netmask/hosts count coverted by table */ + + int shortlisting:1; /* gather only total statistics (set for tables created with --ashort switch) */ + int timesrc:1; /* update time when accounting outgoing traffic */ + int timedst:1; /* update time when accounting incomming traffic */ + + union { /* statistics for each ip in network/netmask */ + struct t_ipt_account_stats_long *l; + struct t_ipt_account_stats_short *s; + } stats; + rwlock_t stats_lock; /* lock, to assure that above union can be safely modified */ + + struct proc_dir_entry *pde; /* handle to proc entry */ +}; + +static LIST_HEAD(ipt_account_tables); +static rwlock_t ipt_account_lock = RW_LOCK_UNLOCKED; /* lock, to assure that table list can be safely modified */ +static DECLARE_MUTEX(ipt_account_mutex); /* additional checkentry protection */ + +static struct file_operations ipt_account_proc_fops; +static struct proc_dir_entry *ipt_account_procdir; + +/* + * Function creates new table and inserts it into linked list. + */ +static struct t_ipt_account_table * +ipt_account_table_init(struct t_ipt_account_info *info) +{ + struct t_ipt_account_table *table; + +#ifdef IPT_ACCOUNT_DEBUG + if (debug) printk(KERN_DEBUG "ipt_account [ipt_account_table_init]: name = %s\n", info->name); +#endif + + /* + * Allocate memory for table. + */ + table = vmalloc(sizeof(struct t_ipt_account_table)); + if (!table) { + printk(KERN_ERR "ipt_account [ipt_account_table_init]: table = vmalloc(sizeof(struct t_ipt_account_table)) failed.\n"); + goto cleanup_none; + } + memset(table, 0, sizeof(struct t_ipt_account_table)); + + /* + * Table attributes. + */ + strncpy(table->name, info->name, IPT_ACCOUNT_NAME_LEN); + table->name[IPT_ACCOUNT_NAME_LEN] = '\0'; + + table->network = info->network; + table->netmask = info->netmask; + table->count = (0xffffffff ^ table->netmask) + 1; + + /* + * Table properties. + */ + table->shortlisting = info->shortlisting; + table->timesrc = 1; + table->timedst = 1; + + /* + * Initialize use counter. + */ + atomic_set(&table->use, 1); + + /* + * Allocate memory for statistic counters. + */ + if (table->shortlisting) { + table->stats.s = vmalloc(sizeof(struct t_ipt_account_stats_short) * table->count); + if (!table->stats.s) { + printk(KERN_ERR "ipt_account [ipt_account_table_init]: table->stats.s = vmalloc(sizeof(struct t_ipt_account_stats_short) * table->count) failed.\n"); + goto cleanup_table; + } + memset(table->stats.s, 0, sizeof(struct t_ipt_account_stats_short) * table->count); + } else { + table->stats.l = vmalloc(sizeof(struct t_ipt_account_stats_long) * table->count); + if (!table->stats.l) { + printk(KERN_ERR "ipt_account [ipt_account_table_init]: table->stats.l = vmalloc(sizeof(struct t_ipt_account_stats_long) * table->count) failed.\n"); + goto cleanup_table; + } + memset(table->stats.l, 0, sizeof(struct t_ipt_account_stats_long) * table->count); + } + + /* + * Reset locks. + */ + table->stats_lock = RW_LOCK_UNLOCKED; + + /* + * Create /proc/ipt_account/name entry. + */ + table->pde = create_proc_entry(table->name, S_IWUSR | S_IRUSR, ipt_account_procdir); + if (!table->pde) { + goto cleanup_stats; + } + table->pde->proc_fops = &ipt_account_proc_fops; + table->pde->data = table; + + /* + * Insert table into list. + */ + write_lock_bh(&ipt_account_lock); + list_add(&table->list, &ipt_account_tables); + write_unlock_bh(&ipt_account_lock); + + return table; + + /* + * If something goes wrong we end here. + */ +cleanup_stats: + if (table->shortlisting) + vfree(table->stats.s); + else + vfree(table->stats.l); + +cleanup_table: + vfree(table); +cleanup_none: + return NULL; + +} + +/* + * Function destroys table. Table *must* be already unlinked. + */ +static void +ipt_account_table_destroy(struct t_ipt_account_table *table) +{ +#ifdef IPT_ACCOUNT_DEBUG + if (debug) printk(KERN_DEBUG "ipt_account [ipt_account_table_destory]: name = %s\n", table->name); +#endif + remove_proc_entry(table->pde->name, table->pde->parent); + if (table->shortlisting) + vfree(table->stats.s); + else + vfree(table->stats.l); + vfree(table); +} + +/* + * Function increments use counter for table. + */ +static inline void +ipt_account_table_get(struct t_ipt_account_table *table) +{ +#ifdef IPT_ACCOUNT_DEBUG + if (debug) printk(KERN_DEBUG "ipt_account [ipt_account_table_get]: name = %s\n", table->name); +#endif + atomic_inc(&table->use); +} + +/* + * Function decrements use counter for table. If use counter drops to zero, + * table is removed from linked list and destroyed. + */ +static inline void +ipt_account_table_put(struct t_ipt_account_table *table) +{ +#ifdef IPT_ACCOUNT_DEBUG + if (debug) printk(KERN_DEBUG "ipt_account [ipt_account_table_put]: name = %s\n", table->name); +#endif + if (atomic_dec_and_test(&table->use)) { + write_lock_bh(&ipt_account_lock); + list_del(&table->list); + write_unlock_bh(&ipt_account_lock); + ipt_account_table_destroy(table); + } +} + +/* + * Helper function, which returns a structure pointer to a table with + * specified name. + */ +static struct t_ipt_account_table * +__ipt_account_table_find(char *name) +{ + struct list_head *pos; + list_for_each(pos, &ipt_account_tables) { + struct t_ipt_account_table *table = list_entry(pos, + struct t_ipt_account_table, list); + if (!strncmp(table->name, name, IPT_ACCOUNT_NAME_LEN)) + return table; + } + return NULL; +} + +/* + * Function, which returns a structure pointer to a table with + * specified name. When such table is found its use coutner + * is incremented. + */ +static inline struct t_ipt_account_table * +ipt_account_table_find_get(char *name) +{ + struct t_ipt_account_table *table; + +#ifdef IPT_ACCOUNT_DEBUG + if (debug) printk(KERN_DEBUG "ipt_account [ipt_account_table_find_get]: name = %s\n", name); +#endif + read_lock_bh(&ipt_account_lock); + table = __ipt_account_table_find(name); + if (!table) { + read_unlock_bh(&ipt_account_lock); + return NULL; + } + atomic_inc(&table->use); + read_unlock_bh(&ipt_account_lock); + return table; +} + +/* + * Helper function, with updates statistics for specified IP. It's only + * used for tables created without --ashort switch. + */ +static inline void +__account_long(struct t_ipt_account_stat_long *stat, const struct sk_buff *skb) +{ + stat->b_all += skb->len; + stat->p_all++; + + switch (skb->nh.iph->protocol) { + case IPPROTO_TCP: + stat->b_tcp += skb->len; + stat->p_tcp++; + break; + case IPPROTO_UDP: + stat->b_udp += skb->len; + stat->p_udp++; + break; + case IPPROTO_ICMP: + stat->b_icmp += skb->len; + stat->p_icmp++; + break; + default: + stat->b_other += skb->len; + stat->p_other++; + } +} + +/* + * Same as above, but used for tables created with --ashort switch. + */ +static inline void +__account_short(struct t_ipt_account_stat_short *stat, const struct sk_buff *skb) +{ + stat->b_all += skb->len; + stat->p_all++; +} + +/* + * Match function. Here we do accounting stuff. + */ +static int +match(const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const void *matchinfo, + int offset, + const void *hdr, + u_int16_t datalen, + int *hotdrop) +{ + struct t_ipt_account_info *info = (struct t_ipt_account_info *)matchinfo; + struct t_ipt_account_table *table = info->table; + u_int32_t address; + /* Get current time. */ + struct timespec now; + jiffies_to_timespec(jiffies, &now); + /* Default we assume no match. */ + int ret = 0; + +#ifdef IPT_ACCOUNT_DEBUG + if (debug) printk(KERN_DEBUG "ipt_account [match]: name = %s\n", table->name); +#endif + /* Check whether traffic from source ip address ... */ + address = ntohl(skb->nh.iph->saddr); + /* ... is being accounted by this table. */ + if (address && ((u_int32_t)(address & table->netmask) == (u_int32_t)table->network)) { + write_lock_bh(&table->stats_lock); + /* Yes, account this packet. */ +#ifdef IPT_ACCOUNT_DEBUG + if (debug) printk(KERN_DEBUG "ipt_account: [match]: accounting packet src = %u.%u.%u.%u, proto = %u.\n", HIPQUAD(address), skb->nh.iph->protocol); +#endif + /* Update counters this host. */ + if (!table->shortlisting) { + __account_long(&table->stats.l[address - table->network].src, skb); + if (table->timesrc) + table->stats.l[address - table->network].time = now; + /* Update also counters for all hosts in this table (network address) */ + if (table->count > 1) { + __account_long(&table->stats.l[0].src, skb); + table->stats.l[0].time = now; + } + } else { + __account_short(&table->stats.s[address - table->network].src, skb); + if (table->timedst) + table->stats.s[address - table->network].time = now; + if (table->count > 1) { + __account_short(&table->stats.s[0].src, skb); + table->stats.s[0].time = now; + } + } + write_unlock_bh(&table->stats_lock); + /* Yes, it's a match. */ + ret = 1; + } + + /* Do the same thing with destination ip address. */ + address = ntohl(skb->nh.iph->daddr); + if (address && ((u_int32_t)(address & table->netmask) == (u_int32_t)table->network)) { + write_lock_bh(&table->stats_lock); +#ifdef IPT_ACCOUNT_DEBUG + if (debug) printk(KERN_DEBUG "ipt_account: [match]: accounting packet dst = %u.%u.%u.%u, proto = %u.\n", HIPQUAD(address), skb->nh.iph->protocol); +#endif + if (!table->shortlisting) { + __account_long(&table->stats.l[address - table->network].dst, skb); + table->stats.l[address - table->network].time = now; + if (table->count > 1) { + __account_long(&table->stats.l[0].dst, skb); + table->stats.l[0].time = now; + } + } else { + __account_short(&table->stats.s[address - table->network].dst, skb); + table->stats.s[address - table->network].time = now; + if (table->count > 1) { + __account_short(&table->stats.s[0].dst, skb); + table->stats.s[0].time = now; + } + } + write_unlock_bh(&table->stats_lock); + ret = 1; + } + + return ret; +} + +/* + * Checkentry function. + */ +static int +checkentry(const char *tablename, + const struct ipt_ip *ipt_ip, + void *matchinfo, + unsigned int matchsize, + unsigned int hook_mask) +{ + struct t_ipt_account_info *info = matchinfo; + struct t_ipt_account_table *table; + +#ifdef IPT_ACCOUNT_DEBUG + if (debug) printk(KERN_DEBUG "ipt_account [checkentry]: name = %s\n", info->name); +#endif + if (matchsize != IPT_ALIGN(sizeof(struct t_ipt_account_info))) + return 0; + + /* + * Sanity checks. + */ + if (info->netmask < ((~0L << (32 - netmask)) & 0xffffffff)) { + printk(KERN_ERR "ipt_account[checkentry]: too big netmask (increase module 'netmask' parameter).\n"); + return 0; + } + if ((info->network & info->netmask) != info->network) { + printk(KERN_ERR "ipt_account[checkentry]: wrong network/netmask.\n"); + return 0; + } + if (info->name[0] == '\0') { + printk(KERN_ERR "ipt_account[checkentry]: wrong table name.\n"); + return 0; + } + + /* + * We got new rule. Try to find table with the same name as given in info structure. + * Mutex magic based on ipt_hashlimit.c. + */ + down(&ipt_account_mutex); + table = ipt_account_table_find_get(info->name); + if (table) { + if (info->table != NULL) { + if (info->table != table) { + /* + * Shouldn't happen. + */ + printk(KERN_ERR "ipt_account[checkentry]: reloaded rule has invalid table pointer.\n"); + up(&ipt_account_mutex); + return 0; + } + up(&ipt_account_mutex); + return 1; + } else { +#ifdef IPT_ACCOUNT_DEBUG + if (debug) printk(KERN_DEBUG "ipt_account [checkentry]: table found, checking.\n"); +#endif + /* + * Table exists, but whether rule network/netmask/shortlisting matches + * table network/netmask/shortlisting. Failure on missmatch. + */ + if (table->network != info->network || table->netmask != info->netmask || table->shortlisting != info->shortlisting) { + printk(KERN_ERR "ipt_account [checkentry]: table found, rule network/netmask/shortlisting not match table network/netmask/shortlisting.\n"); + /* + * Remember to release table usage counter. + */ + ipt_account_table_put(table); + up(&ipt_account_mutex); + return 0; + } +#ifdef IPT_ACCOUNT_DEBUG + if (debug) printk(KERN_DEBUG "ipt_account [checkentry]: table found, reusing.\n"); +#endif + /* + * Link rule with table. + */ + info->table = table; + } + } else { +#ifdef IPT_ACCOUNT_DEBUG + if (debug) printk(KERN_DEBUG "ipt_account [checkentry]: table not found, creating new one.\n"); +#endif + /* + * Table not exist, create new one. + */ + info->table = table = ipt_account_table_init(info); + if (!table) { + up(&ipt_account_mutex); + return 0; + } + } + up(&ipt_account_mutex); + return 1; +} + +/* + * Destroy function. + */ +static void +destroy(void *matchinfo, unsigned int matchsize) +{ + struct t_ipt_account_info *info = matchinfo; + +#ifdef IPT_ACCOUNT_DEBUG + if (debug) printk(KERN_DEBUG "ipt_account [destroy]: name = %s\n", info->name); +#endif + /* + * Release table, by decreasing its usage counter. When + * counter hits zero, memory used by table structure is + * released and table is removed from list. + */ + ipt_account_table_put(info->table); + return; +} + +static struct ipt_match account_match = { + .name = "account", + .match = &match, + .checkentry = &checkentry, + .destroy = &destroy, + .me = THIS_MODULE +}; + +/* + * Below functions (ipt_account_seq_start, ipt_account_seq_next, + * ipt_account_seq_stop, ipt_account_seq_show, ipt_account_proc_write) + * are used to implement proc stuff. + */ +static void *ipt_account_seq_start(struct seq_file *sf, loff_t *pos) +{ + struct proc_dir_entry *pde = sf->private; + struct t_ipt_account_table *table = pde->data; + unsigned int *i; + + read_lock_bh(&table->stats_lock); + if (*pos >= table->count) + return NULL; + i = kmalloc(sizeof(unsigned int), GFP_ATOMIC); + if (!i) + return ERR_PTR(-ENOMEM); + *i = *pos; + return i; +} + +static void *ipt_account_seq_next(struct seq_file *sf, void *v, loff_t *pos) +{ + struct proc_dir_entry *pde = sf->private; + struct t_ipt_account_table *table = pde->data; + unsigned int *i = (unsigned int *)v; + + *pos = ++(*i); + if (*i >= table->count) { + kfree(v); + return NULL; + } + return i; +} + +static void ipt_account_seq_stop(struct seq_file *sf, void *v) +{ + struct proc_dir_entry *pde = sf->private; + struct t_ipt_account_table *table = pde->data; + kfree(v); + read_unlock_bh(&table->stats_lock); +} + +static int ipt_account_seq_show(struct seq_file *sf, void *v) +{ + struct proc_dir_entry *pde = sf->private; + struct t_ipt_account_table *table = pde->data; + unsigned int *i = (unsigned int *)v; + + struct timespec now; + jiffies_to_timespec(jiffies, &now); + + u_int32_t address = table->network + *i; + + if (!table->shortlisting) { + struct t_ipt_account_stats_long *l = &table->stats.l[*i]; + seq_printf(sf, + "ip = %u.%u.%u.%u bytes_src = %Lu %Lu %Lu %Lu %Lu packets_src = %Lu %Lu %Lu %Lu %Lu bytes_dst = %Lu %Lu %Lu %Lu %Lu packets_dst = %Lu %Lu %Lu %Lu %Lu time = %lu\n", + HIPQUAD(address), + l->src.b_all, + l->src.b_tcp, + l->src.b_udp, + l->src.b_icmp, + l->src.b_other, + l->src.p_all, + l->src.p_tcp, + l->src.p_udp, + l->src.p_icmp, + l->src.p_other, + l->dst.b_all, + l->dst.b_tcp, + l->dst.b_udp, + l->dst.b_icmp, + l->dst.b_other, + l->dst.p_all, + l->dst.p_tcp, + l->dst.p_udp, + l->dst.p_icmp, + l->dst.p_other, + now.tv_sec - l->time.tv_sec + ); + } else { + struct t_ipt_account_stats_short *s = &table->stats.s[*i]; + seq_printf(sf, + "ip = %u.%u.%u.%u bytes_src = %Lu packets_src = %Lu bytes_dst = %Lu packets_dst = %Lu time = %lu\n", + HIPQUAD(address), + s->src.b_all, + s->src.p_all, + s->dst.b_all, + s->dst.p_all, + now.tv_sec - s->time.tv_sec + ); + } + + return 0; +} + +static struct seq_operations ipt_account_seq_ops = { + .start = ipt_account_seq_start, + .next = ipt_account_seq_next, + .stop = ipt_account_seq_stop, + .show = ipt_account_seq_show +}; + +static ssize_t ipt_account_proc_write(struct file *file, const char __user *input, size_t size, loff_t *ofs) +{ + char buffer[1024]; + struct proc_dir_entry *pde = PDE(file->f_dentry->d_inode); + struct t_ipt_account_table *table = pde->data; + + u_int32_t o[4], ip; + struct t_ipt_account_stats_long l; + struct t_ipt_account_stats_short s; + +#ifdef IPT_ACCOUNT_DEBUG + if (debug) printk(KERN_DEBUG "ipt_account [ipt_account_proc_write]: name = %s.\n", table->name); +#endif + if (copy_from_user(buffer, input, 1024)) + return -EFAULT; + buffer[1023] = '\0'; + + if (!strncmp(buffer, "reset\n", 6)) { + /* + * User requested to clear all table. Ignorant, does + * he known how match time it took us to fill it? ;-) + */ + write_lock_bh(&table->stats_lock); + if (table->shortlisting) + memset(table->stats.s, 0, sizeof(struct t_ipt_account_stats_short) * table->count); + else + memset(table->stats.l, 0, sizeof(struct t_ipt_account_stats_long) * table->count); + write_unlock_bh(&table->stats_lock); + } else if (!strncmp(buffer, "time=any\n", 9)) { + table->timesrc = table->timedst = 1; + } else if (!strncmp(buffer, "time=src\n", 9)) { + table->timesrc = 1; + table->timedst = 0; + } else if (!strncmp(buffer, "time=dst\n", 9)) { + table->timesrc = 0; + table->timedst = 1; + } else if (!table->shortlisting && sscanf(buffer, "ip = %u.%u.%u.%u bytes_src = %Lu %Lu %Lu %Lu %Lu packets_src = %Lu %Lu %Lu %Lu %Lu bytes_dst = %Lu %Lu %Lu %Lu %Lu packets_dst = %Lu %Lu %Lu %Lu %Lu time = %lu", + &o[0], &o[1], &o[2], &o[3], + &l.src.b_all, &l.src.b_tcp, &l.src.b_udp, &l.src.b_icmp, &l.src.b_other, + &l.src.p_all, &l.src.p_tcp, &l.src.p_udp, &l.src.p_icmp, &l.src.p_other, + &l.dst.b_all, &l.dst.b_tcp, &l.dst.b_udp, &l.dst.b_icmp, &l.dst.b_other, + &l.dst.p_all, &l.dst.p_tcp, &l.dst.p_udp, &l.dst.p_icmp, &l.dst.p_other, + &l.time.tv_sec) == 25) { + /* + * We got line formated like long listing row. We have to + * check, if IP is accounted by table. If so, we + * simply replace row with user's one. + */ + ip = o[0] << 24 | o[1] << 16 | o[2] << 8 | o[3]; + if ((u_int32_t)(ip & table->netmask) == (u_int32_t)table->network) { + /* + * Ignore user input time. Set current time. + */ + jiffies_to_timespec(jiffies, &l.time); + write_lock_bh(&table->stats_lock); + table->stats.l[ip - table->network] = l; + write_unlock_bh(&table->stats_lock); + } + } else if (table->shortlisting && sscanf(buffer, "ip = %u.%u.%u.%u bytes_src = %Lu packets_src = %Lu bytes_dst = %Lu packets_dst = %Lu time = %lu\n", + &o[0], &o[1], &o[2], &o[3], + &s.src.b_all, + &s.src.p_all, + &s.dst.b_all, + &s.dst.p_all, + &s.time.tv_sec) == 9) { + /* + * We got line formated like short listing row. Do the + * same action like above. + */ + ip = o[0] << 24 | o[1] << 16 | o[2] << 8 | o[3]; + if ((u_int32_t)(ip & table->netmask) == (u_int32_t)table->network) { + jiffies_to_timespec(jiffies, &s.time); + write_lock_bh(&table->stats_lock); + table->stats.s[ip - table->network] = s; + write_unlock_bh(&table->stats_lock); + } + } else { + /* + * We don't understand what user have just wrote. + */ + return -EIO; + } + + return size; +} + +static int ipt_account_proc_open(struct inode *inode, struct file *file) +{ + int ret = seq_open(file, &ipt_account_seq_ops); + if (!ret) { + struct seq_file *sf = file->private_data; + struct proc_dir_entry *pde = PDE(inode); + struct t_ipt_account_table *table = pde->data; + + sf->private = pde; + + ipt_account_table_get(table); + } + return ret; +} + +static int ipt_account_proc_release(struct inode *inode, struct file *file) +{ + struct proc_dir_entry *pde = PDE(inode); + struct t_ipt_account_table *table = pde->data; + int ret; + + ret = seq_release(inode, file); + + if (!ret) + ipt_account_table_put(table); + + return ret; +} + +static struct file_operations ipt_account_proc_fops = { + .owner = THIS_MODULE, + .open = ipt_account_proc_open, + .read = seq_read, + .write = ipt_account_proc_write, + .llseek = seq_lseek, + .release = ipt_account_proc_release +}; + +/* + * Module init function. + */ +static int __init init(void) +{ + int ret = 0; + + printk(KERN_INFO "ipt_account %s : Piotr Gasidlo , http://www.barbara.eu.org/~quaker/ipt_account/\n", IPT_ACCOUNT_VERSION); + + /* Check module parameters. */ + if (netmask > 32 || netmask < 0) { + printk(KERN_ERR "ipt_account[__init]: Wrong netmask given as parameter (%i). Valid is 32 to 0.\n", netmask); + ret = -EINVAL; + goto cleanup_none; + } + + /* Register match. */ + if (ipt_register_match(&account_match)) { + ret = -EINVAL; + goto cleanup_none; + } + + /* Create /proc/net/ipt_account/ entry. */ + ipt_account_procdir = proc_mkdir("ipt_account", proc_net); + if (!ipt_account_procdir) { + printk(KERN_ERR "ipt_account [__init]: ipt_account_procdir = proc_mkdir(\"ipt_account\", proc_net) failed.\n"); + ret = -ENOMEM; + goto cleanup_match; + } + + return ret; + + /* If something goes wrong we end here. */ +cleanup_match: + ipt_unregister_match(&account_match); +cleanup_none: + return ret; +} + +/* + * Module exit function. + */ +static void __exit fini(void) +{ + /* Remove /proc/net/ipt_account/ */ + remove_proc_entry(ipt_account_procdir->name, ipt_account_procdir->parent); + ipt_unregister_match(&account_match); +} + +module_init(init); +module_exit(fini); + diff --git a/release/src/router/cstats/cstats.c b/release/src/router/cstats/cstats.c index fdd68b2b32..fc2de5f553 100644 --- a/release/src/router/cstats/cstats.c +++ b/release/src/router/cstats/cstats.c @@ -640,11 +640,16 @@ static void calc(void) { while (fgets(buf, sizeof(buf), f)) { // _dprintf("%s: read\n", __FUNCTION__); if(sscanf(buf, +/* #if defined(LINUX26) "ip = %s bytes_src = %lu %*u %*u %*u %*u packets_src = %*u %*u %*u %*u %*u bytes_dst = %lu %*u %*u %*u %*u packets_dst = %*u %*u %*u %*u %*u time = %*u", #else "ip = %s bytes_src = %lu %*u %*u %*u %*u packets_src = %*u %*u %*u %*u %*u bytes_dest = %lu %*u %*u %*u %*u packets_dest = %*u %*u %*u %*u %*u time = %*u", #endif +*/ + + "ip = %s bytes_src = %lu %*u %*u %*u %*u packets_src = %*u %*u %*u %*u %*u bytes_dst = %lu %*u %*u %*u %*u packets_dst = %*u %*u %*u %*u %*u time = %*u", +// "ip = %s bytes_src = %Lu %*Lu %*Lu %*Lu %*Lu packets_src = %*Lu %*Lu %*Lu %*Lu %*Lu bytes_dest = %Lu %*Lu %*Lu %*Lu %*Lu packets_dest = %*Lu %*Lu %*Lu %*Lu %*Lu time = %*lu", ip, &rx, &tx) != 3 ) continue; // _dprintf("%s: %s tx=%lu rx=%lu\n", __FUNCTION__, ip, tx, rx); diff --git a/release/src/router/iptables/extensions/libipt_account.c b/release/src/router/iptables/extensions/libipt_account.c dissimilarity index 80% index 305b5980f2..6d9d85a0d2 100644 --- a/release/src/router/iptables/extensions/libipt_account.c +++ b/release/src/router/iptables/extensions/libipt_account.c @@ -1,368 +1,281 @@ -/* Copyright (c) 2004-2009 Piotr 'QuakeR' Gasidlo - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - */ - -#include -#include -#ifdef IPTABLES_VERSION -#include -#elif defined XTABLES_VERSION -#include -#else -#error IPTABLES_VERSION nor XTABLES_VERSION not defined. -#endif -#include -#include - -#include - -#ifndef HIPQUAD -#define HIPQUAD(addr) \ - ((unsigned char *)&addr)[3], \ - ((unsigned char *)&addr)[2], \ - ((unsigned char *)&addr)[1], \ - ((unsigned char *)&addr)[0] -#endif - -static void help(void) { - printf( - "account v%s options:\n" - "--aaddr network/netmask\n" - " defines network/netmask for which make statistics.\n" - "--aname name\n" - " defines name of list where statistics will be kept. If no is\n" - " specified DEFAULT will be used.\n" - "--ashort\n" - " table will colect only short statistics (only total counters\n" - " without splitting it into protocols.\n" - , -#ifdef IPTABLES_VERSION - IPTABLES_VERSION -#else - XTABLES_VERSION -#endif - ); -}; - -static struct option opts[] = { - { .name = "aaddr", .has_arg = 1, .flag = NULL, .val = 201 }, - { .name = "aname", .has_arg = 1, .flag = NULL, .val = 202 }, - { .name = "ashort", .has_arg = 0, .flag = NULL, .val = 203 }, - { .name = 0, .has_arg = 0, .flag = 0, .val = 0 } -}; - -/* Helper functions for parse_network */ -int parseip(const char *parameter, u_int32_t *ip) { - - char buffer[16], *bufferptr, *dot; - unsigned int i, shift, part; - - if (strlen(parameter) > 15) - return 0; - - strncpy(buffer, parameter, 15); - buffer[15] = 0; - - bufferptr = buffer; - - for (i = 0, shift = 24, *ip = 0; i < 3; i++, shift -= 8) { - /* no dot */ - if ((dot = strchr(bufferptr, '.')) == NULL) - return 0; - /* not a number */ - if ((part = strtol(bufferptr, (char**)NULL, 10)) < 0) - return 0; - /* to big number */ - if (part > 255) - return 0; - *ip |= part << shift; - bufferptr = dot + 1; - } - /* not a number */ - if ((part = strtol(bufferptr, (char**)NULL, 10)) < 0) - return 0; - /* to big number */ - if (part > 255) - return 0; - *ip |= part; - return 1; -} - -static void parsenetwork(const char *parameter, u_int32_t *network) { - if (!parseip(parameter, network)) -#ifdef XTABLES_VERSION - xtables_error(PARAMETER_PROBLEM, "account: wrong ip in network"); -#else - exit_error(PARAMETER_PROBLEM, "account: wrong ip in network"); -#endif -} - -static void parsenetmaskasbits(const char *parameter, u_int32_t *netmask) { - - u_int32_t bits; - - if ((bits = strtol(parameter, (char **)NULL, 10)) < 0 || bits > 32) -#ifdef XTABLES_VERSION - xtables_error(PARAMETER_PROBLEM, "account: wrong netmask"); -#else - exit_error(PARAMETER_PROBLEM, "account: wrong netmask"); -#endif - - *netmask = 0xffffffff << (32 - bits); -} - -static void parsenetmaskasip(const char *parameter, u_int32_t *netmask) { - if (!parseip(parameter, netmask)) -#ifdef XTABLES_VERSION - xtables_error(PARAMETER_PROBLEM, "account: wrong ip in netmask"); -#else - exit_error(PARAMETER_PROBLEM, "account: wrong ip in netmask"); -#endif -} - -static void parsenetmask(const char *parameter, u_int32_t *netmask) -{ - if (strchr(parameter, '.') != NULL) - parsenetmaskasip(parameter, netmask); - else - parsenetmaskasbits(parameter, netmask); -} - -static void parsenetworkandnetmask(const char *parameter, u_int32_t *network, u_int32_t *netmask) -{ - - char buffer[32], *slash; - - if (strlen(parameter) > 31) - /* text is to long, even for 255.255.255.255/255.255.255.255 */ -#ifdef XTABLES_VERSION - xtables_error(PARAMETER_PROBLEM, "account: wrong network/netmask"); -#else - exit_error(PARAMETER_PROBLEM, "account: wrong network/netmask"); -#endif - - strncpy(buffer, parameter, 31); - buffer[31] = 0; - - /* check whether netmask is given */ - if ((slash = strchr(buffer, '/')) != NULL) { - parsenetmask(slash + 1, netmask); - *slash = 0; - } else - *netmask = 0xffffffff; - parsenetwork(buffer, network); - - if ((*network & *netmask) != *network) -#ifdef XTABLES_VERSION - xtables_error(PARAMETER_PROBLEM, "account: wrong network/netmask"); -#else - exit_error(PARAMETER_PROBLEM, "account: wrong network/netmask"); -#endif -} - - -/* Function gets network & netmask from argument after --aaddr */ -static void parse_network(const char *parameter, struct t_ipt_account_info *info) { - - parsenetworkandnetmask(parameter, &info->network, &info->netmask); - -} - -/* validate netmask */ -inline int valid_netmask(u_int32_t netmask) { - while (netmask & 0x80000000) - netmask <<= 1; - if (netmask != 0) - return 0; - return 1; -} - -/* validate network/netmask pair */ -inline int valid_network_and_netmask(struct t_ipt_account_info *info) { - if (!valid_netmask(info->netmask)) - return 0; - if ((info->network & info->netmask) != info->network) - return 0; - return 1; -} - - - -/* Function initializes match */ -#ifdef XTABLES_VERSION -static void init(struct xt_entry_match *match) -#else -static void init(struct ipt_entry_match *match, - unsigned int *nfcache) -#endif -{ - struct t_ipt_account_info *info = (struct t_ipt_account_info *)(match)->data; - - - /* set default table name to DEFAULT */ - strncpy(info->name, "DEFAULT", IPT_ACCOUNT_NAME_LEN); - info->shortlisting = 0; -#ifdef LINUX26 - info->table = NULL; -#endif - -} - -/* Function parses match's arguments */ -static int parse(int c, - char **argv, - int invert, - unsigned int *flags, -#ifdef XTABLES_VERSION - const void *entry, - struct xt_entry_match **match -#else - const struct ipt_entry *entry, - unsigned int *nfcache, - struct ipt_entry_match **match -#endif - ) -{ - struct t_ipt_account_info *info = (struct t_ipt_account_info *)(*match)->data; - - switch (c) { - - /* --aaddr */ - case 201: - parse_network(optarg, info); - if (!valid_network_and_netmask(info)) -#ifdef XTABLES_VERSION - xtables_error(PARAMETER_PROBLEM, "account: wrong network/netmask"); -#else - exit_error(PARAMETER_PROBLEM, "account: wrong network/netmask"); -#endif - *flags = 1; - break; - - /* --aname */ - case 202: - if (strlen(optarg) < IPT_ACCOUNT_NAME_LEN) { - strncpy(info->name, optarg, IPT_ACCOUNT_NAME_LEN); - info->name[IPT_ACCOUNT_NAME_LEN] = '\0'; - } else -#ifdef XTABLES_VERSION - xtables_error(PARAMETER_PROBLEM, "account: Too long table name"); -#else - exit_error(PARAMETER_PROBLEM, "account: Too long table name"); -#endif - break; - /* --ashort */ - case 203: - info->shortlisting = 1; - break; - default: - return 0; - } - return 1; -} - -/* Final check whether network/netmask was specified */ -static void final_check(unsigned int flags) { - if (!flags) -#ifdef XTABLES_VERSION - xtables_error(PARAMETER_PROBLEM, "account: You need specify '--aaddr' parameter"); -#else - exit_error(PARAMETER_PROBLEM, "account: You need specify '--aaddr' parameter"); -#endif -} - -/* Function used for printing rule with account match for iptables -L */ -static void print( -#ifdef XTABLES_VERSION - const void *ip, - const struct xt_entry_match *match, -#else - const struct ipt_ip *ip, - const struct ipt_entry_match *match, -#endif - int numeric) { - - struct t_ipt_account_info *info = (struct t_ipt_account_info *)match->data; - - printf("account: "); - printf("network/netmask: "); - printf("%u.%u.%u.%u/%u.%u.%u.%u ", - HIPQUAD(info->network), - HIPQUAD(info->netmask) - ); - - printf("name: %s ", info->name); - if (info->shortlisting) - printf("short-listing "); -} - -/* Function used for saving rule containing account match */ -static void save( -#ifdef XTABLES_VERSION - const void *ip, - const struct xt_entry_match *match -#else - const struct ipt_ip *ip, - const struct ipt_entry_match *match -#endif -) { - - struct t_ipt_account_info *info = (struct t_ipt_account_info *)match->data; - - printf("--aaddr "); - printf("%u.%u.%u.%u/%u.%u.%u.%u ", - HIPQUAD(info->network), - HIPQUAD(info->netmask) - ); - - printf("--aname %s ", info->name); - if (info->shortlisting) - printf("--ashort "); -} - -#ifdef XTABLES_VERSION -static struct xtables_match account = { - .name = "account", - .version = XTABLES_VERSION, - .family = PF_INET, - .size = XT_ALIGN(sizeof(struct t_ipt_account_info)), - .userspacesize = XT_ALIGN(sizeof(struct t_ipt_account_info)), - .help = help, - .init = init, - .parse = parse, - .final_check = final_check, - .print = print, - .save = save, - .extra_opts = opts -}; -#else -static struct iptables_match account = { - .next = NULL, - .name = "account", - .version = IPTABLES_VERSION, - .size = IPT_ALIGN(sizeof(struct t_ipt_account_info)), - .userspacesize = IPT_ALIGN(sizeof(struct t_ipt_account_info)), - .help = &help, - .init = &init, - .parse = &parse, - .final_check = &final_check, - .print = &print, - .save = &save, - .extra_opts = opts -}; -#endif - -/* Function which registers match */ -void _init(void) -{ -#ifdef XTABLES_VERSION - xtables_register_match(&account); -#else - register_match(&account); -#endif -} - +/* Copyright (c) 2004-2006 Piotr 'QuakeR' Gasid³o + * accounting match helper (libipt_account.c) + * + * Version: 0.1.20 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include + +#include + +#ifndef HIPQUAD +#define HIPQUAD(addr) \ + ((unsigned char *)&addr)[3], \ + ((unsigned char *)&addr)[2], \ + ((unsigned char *)&addr)[1], \ + ((unsigned char *)&addr)[0] +#endif + +static void help(void) { + printf( + "account v%s options:\n" + "--aaddr network/netmask\n" + " defines network/netmask for which make statistics.\n" + "--aname name\n" + " defines name of list where statistics will be kept. If no is\n" + " specified DEFAULT will be used.\n" + "--ashort\n" + " table will colect only short statistics (only total counters\n" + " without splitting it into protocols.\n" + , + IPTABLES_VERSION); +}; + +static struct option opts[] = { + { .name = "aaddr", .has_arg = 1, .flag = NULL, .val = 201 }, + { .name = "aname", .has_arg = 1, .flag = NULL, .val = 202 }, + { .name = "ashort", .has_arg = 0, .flag = NULL, .val = 203 }, + { .name = 0, .has_arg = 0, .flag = 0, .val = 0 } +}; + +/* Helper functions for parse_network */ +int parseip(const char *parameter, u_int32_t *ip) { + + char buffer[16], *bufferptr, *dot; + unsigned int i, shift, part; + + if (strlen(parameter) > 15) + return 0; + + strncpy(buffer, parameter, 15); + buffer[15] = 0; + + bufferptr = buffer; + + for (i = 0, shift = 24, *ip = 0; i < 3; i++, shift -= 8) { + /* no dot */ + if ((dot = strchr(bufferptr, '.')) == NULL) + return 0; + /* not a number */ + if ((part = strtol(bufferptr, (char**)NULL, 10)) < 0) + return 0; + /* to big number */ + if (part > 255) + return 0; + *ip |= part << shift; + bufferptr = dot + 1; + } + /* not a number */ + if ((part = strtol(bufferptr, (char**)NULL, 10)) < 0) + return 0; + /* to big number */ + if (part > 255) + return 0; + *ip |= part; + return 1; +} + +static void parsenetwork(const char *parameter, u_int32_t *network) { + if (!parseip(parameter, network)) + exit_error(PARAMETER_PROBLEM, "account: wrong ip in network"); +} + +static void parsenetmaskasbits(const char *parameter, u_int32_t *netmask) { + + u_int32_t bits; + + if ((bits = strtol(parameter, (char **)NULL, 10)) < 0 || bits > 32) + exit_error(PARAMETER_PROBLEM, "account: wrong netmask"); + + *netmask = 0xffffffff << (32 - bits); +} + +static void parsenetmaskasip(const char *parameter, u_int32_t *netmask) { + if (!parseip(parameter, netmask)) + exit_error(PARAMETER_PROBLEM, "account: wrong ip in netmask"); +} + +static void parsenetmask(const char *parameter, u_int32_t *netmask) +{ + if (strchr(parameter, '.') != NULL) + parsenetmaskasip(parameter, netmask); + else + parsenetmaskasbits(parameter, netmask); +} + +static void parsenetworkandnetmask(const char *parameter, u_int32_t *network, u_int32_t *netmask) +{ + + char buffer[32], *slash; + + if (strlen(parameter) > 31) + /* text is to long, even for 255.255.255.255/255.255.255.255 */ + exit_error(PARAMETER_PROBLEM, "account: wrong network/netmask"); + + strncpy(buffer, parameter, 31); + buffer[31] = 0; + + /* check whether netmask is given */ + if ((slash = strchr(buffer, '/')) != NULL) { + parsenetmask(slash + 1, netmask); + *slash = 0; + } else + *netmask = 0xffffffff; + parsenetwork(buffer, network); + + if ((*network & *netmask) != *network) + exit_error(PARAMETER_PROBLEM, "account: wrong network/netmask"); +} + + +/* Function gets network & netmask from argument after --aaddr */ +static void parse_network(const char *parameter, struct t_ipt_account_info *info) { + + parsenetworkandnetmask(parameter, &info->network, &info->netmask); + +} + +/* validate netmask */ +inline int valid_netmask(u_int32_t netmask) { + while (netmask & 0x80000000) + netmask <<= 1; + if (netmask != 0) + return 0; + return 1; +} + +/* validate network/netmask pair */ +inline int valid_network_and_netmask(struct t_ipt_account_info *info) { + if (!valid_netmask(info->netmask)) + return 0; + if ((info->network & info->netmask) != info->network) + return 0; + return 1; +} + + + +/* Function initializes match */ +static void init(struct ipt_entry_match *match, + unsigned int *nfcache) { + + struct t_ipt_account_info *info = (struct t_ipt_account_info *)(match)->data; + + + /* set default table name to DEFAULT */ + strncpy(info->name, "DEFAULT", IPT_ACCOUNT_NAME_LEN); + info->shortlisting = 0; + info->table = NULL; + +} + +/* Function parses match's arguments */ +static int parse(int c, char **argv, + int invert, + unsigned int *flags, + const struct ipt_entry *entry, + unsigned int *nfcache, + struct ipt_entry_match **match) { + + struct t_ipt_account_info *info = (struct t_ipt_account_info *)(*match)->data; + + switch (c) { + + /* --aaddr */ + case 201: + parse_network(optarg, info); + if (!valid_network_and_netmask(info)) + exit_error(PARAMETER_PROBLEM, "account: wrong network/netmask"); + *flags = 1; + break; + + /* --aname */ + case 202: + if (strlen(optarg) < IPT_ACCOUNT_NAME_LEN) { + strncpy(info->name, optarg, IPT_ACCOUNT_NAME_LEN); + info->name[IPT_ACCOUNT_NAME_LEN] = '\0'; + } else + exit_error(PARAMETER_PROBLEM, "account: Too long table name"); + break; + /* --ashort */ + case 203: + info->shortlisting = 1; + break; + default: + return 0; + } + return 1; +} + +/* Final check whether network/netmask was specified */ +static void final_check(unsigned int flags) { + if (!flags) + exit_error(PARAMETER_PROBLEM, "account: You need specify '--aaddr' parameter"); +} + +/* Function used for printing rule with account match for iptables -L */ +static void print(const struct ipt_ip *ip, + const struct ipt_entry_match *match, + int numeric) { + + struct t_ipt_account_info *info = (struct t_ipt_account_info *)match->data; + + printf("account: "); + printf("network/netmask: "); + printf("%u.%u.%u.%u/%u.%u.%u.%u ", + HIPQUAD(info->network), + HIPQUAD(info->netmask) + ); + + printf("name: %s ", info->name); + if (info->shortlisting) + printf("short-listing "); +} + +/* Function used for saving rule containing account match */ +static void save(const struct ipt_ip *ip, + const struct ipt_entry_match *match) { + + struct t_ipt_account_info *info = (struct t_ipt_account_info *)match->data; + + printf("--aaddr "); + printf("%u.%u.%u.%u/%u.%u.%u.%u ", + HIPQUAD(info->network), + HIPQUAD(info->netmask) + ); + + printf("--aname %s ", info->name); + if (info->shortlisting) + printf("--ashort "); +} + +static struct iptables_match account = { + .next = NULL, + .name = "account", + .version = IPTABLES_VERSION, + .size = IPT_ALIGN(sizeof(struct t_ipt_account_info)), + .userspacesize = IPT_ALIGN(sizeof(struct t_ipt_account_info)), + .help = &help, + .init = &init, + .parse = &parse, + .final_check = &final_check, + .print = &print, + .save = &save, + .extra_opts = opts +}; + +/* Function which registers match */ +void _init(void) +{ + register_match(&account); +} + + diff --git a/release/src/router/rc/Makefile b/release/src/router/rc/Makefile index 8007202087..48aefcf390 100644 --- a/release/src/router/rc/Makefile +++ b/release/src/router/rc/Makefile @@ -14,7 +14,6 @@ OBJS := rc.o init.o interface.o network.o wan.o services.o dhcp.o OBJS += firewall.o ppp.o telssh.o wnas.o OBJS += listen.o redial.o led.o qos.o forward.o misc.o mtd.o OBJS += buttons.o restrict.o gpio.o sched.o -OBJS += account.o OBJS += arpbind.o OBJS += qoslimit.o # heartbeat.o diff --git a/release/src/router/rc/account.c b/release/src/router/rc/account.c deleted file mode 100644 index 8099ccaf07..0000000000 --- a/release/src/router/rc/account.c +++ /dev/null @@ -1,72 +0,0 @@ -/* - account.c - - Bandwidth monitoring enhancements for Tomato firmware - Copyright (C) 2011 Augusto Bott - http://code.google.com/p/tomato-sdhc-vlan/ - -*/ - -#include "rc.h" -#include - -void accountoneachbridge(int enable); - -void start_account(void) { - accountoneachbridge(0); - accountoneachbridge(1); -} - -void stop_account(void) { - accountoneachbridge(0); -} - -void accountoneachbridge(int enable) { - - struct in_addr ipaddr; - struct in_addr netmask; - struct in_addr network; - - char lanN_ifname[] = "lanXX_ifname"; - char lanN_ipaddr[] = "lanXX_ipaddr"; - char lanN_netmask[] = "lanXX_netmask"; - char lanN[] = "lanXX"; - char netaddrnetmask[] = "255.255.255.255/255.255.255.255 "; - char br; - - for(br=0 ; br<=3 ; br++) { - char bridge[2] = "0"; - if (br!=0) - bridge[0]+=br; - else - strcpy(bridge, ""); - - sprintf(lanN_ifname, "lan%s_ifname", bridge); - - if (strcmp(nvram_safe_get(lanN_ifname), "")!=0) { - - sprintf(lanN_ipaddr, "lan%s_ipaddr", bridge); - sprintf(lanN_netmask, "lan%s_netmask", bridge); - sprintf(lanN, "lan%s", bridge); - - inet_aton(nvram_safe_get(lanN_ipaddr), &ipaddr); - inet_aton(nvram_safe_get(lanN_netmask), &netmask); - - // bitwise AND of ip and netmask gives the network - network.s_addr = ipaddr.s_addr & netmask.s_addr; - - sprintf(netaddrnetmask, "%s/%s", inet_ntoa(network), nvram_safe_get(lanN_netmask)); - - if (enable == 1) { - // iptables -I FORWARD 1 -m account --aaddr 192.168.0.0/255.255.255.0 --aname mynetwork -// cprintf("ipt_account: iptables -I FORWARD 1 -m account --aaddr %s --aname %s\n", netaddrnetmask, lanN); - eval("iptables", "-I", "FORWARD", "1", "-m", "account", "--aaddr", netaddrnetmask, "--aname", lanN); - } else { - // iptables -D FORWARD -m account --aaddr 192.168.0.0/255.255.255.0 --aname mynetwork -// cprintf("ipt_account: iptables -D FORWARD -m account --aaddr %s --aname %s\n", netaddrnetmask, lanN); - eval("iptables", "-D", "FORWARD", "-m", "account", "--aaddr", netaddrnetmask, "--aname", lanN); - } - } - } -} - diff --git a/release/src/router/rc/firewall.c b/release/src/router/rc/firewall.c index 755ba7f09d..6bf791c6a7 100644 --- a/release/src/router/rc/firewall.c +++ b/release/src/router/rc/firewall.c @@ -417,6 +417,44 @@ int ipt_layer7(const char *v, char *opt) return 1; } +// ----------------------------------------------------------------------------- + +static void ipt_account(void) { + struct in_addr ipaddr, netmask, network; + char lanN_ifname[] = "lanXX_ifname"; + char lanN_ipaddr[] = "lanXX_ipaddr"; + char lanN_netmask[] = "lanXX_netmask"; + char lanN[] = "lanXX"; + char netaddrnetmask[] = "255.255.255.255/255.255.255.255 "; + char br; + + for(br=0 ; br<=3 ; br++) { + char bridge[2] = "0"; + if (br!=0) + bridge[0]+=br; + else + strcpy(bridge, ""); + + sprintf(lanN_ifname, "lan%s_ifname", bridge); + + if (strcmp(nvram_safe_get(lanN_ifname), "")!=0) { + + sprintf(lanN_ipaddr, "lan%s_ipaddr", bridge); + sprintf(lanN_netmask, "lan%s_netmask", bridge); + sprintf(lanN, "lan%s", bridge); + + inet_aton(nvram_safe_get(lanN_ipaddr), &ipaddr); + inet_aton(nvram_safe_get(lanN_netmask), &netmask); + + // bitwise AND of ip and netmask gives the network + network.s_addr = ipaddr.s_addr & netmask.s_addr; + + sprintf(netaddrnetmask, "%s/%s", inet_ntoa(network), nvram_safe_get(lanN_netmask)); + + ipt_write("-A FORWARD -m account --aaddr %s --aname %s\n", netaddrnetmask, lanN); + } + } +} // ----------------------------------------------------------------------------- @@ -1222,6 +1260,8 @@ static void filter_log(void) limit[0] = 0; } + ipt_account(); + #ifdef TCONFIG_IPV6 modprobe("ip6t_LOG"); #endif @@ -1697,7 +1737,6 @@ int start_firewall(void) #endif run_nvscript("script_fire", NULL, 1); - start_account(); start_arpbind(); #ifdef LINUX26 diff --git a/release/src/router/rc/rc.h b/release/src/router/rc/rc.h index 5372a2516a..c06e697699 100644 --- a/release/src/router/rc/rc.h +++ b/release/src/router/rc/rc.h @@ -296,10 +296,6 @@ extern void allow_fastnat(const char *service, int allow); extern void try_enabling_fastnat(void); #endif -// account.c -extern void start_account(void); -extern void stop_account(void); - // arpbind.c extern void start_arpbind(void); extern void stop_arpbind(void); diff --git a/release/src/router/rc/services.c b/release/src/router/rc/services.c index 455f861a52..1e6f1e6502 100644 --- a/release/src/router/rc/services.c +++ b/release/src/router/rc/services.c @@ -2187,18 +2187,6 @@ TOP: goto CLEAR; } - if (strcmp(service, "account") == 0) { - if (action & A_STOP) stop_account(); - if (action & A_START) start_account(); - goto CLEAR; - } - - if (strcmp(service, "arpbind") == 0) { - if (action & A_STOP) stop_arpbind(); - if (action & A_START) start_arpbind(); - goto CLEAR; - } - if (strcmp(service, "restrict") == 0) { if (action & A_STOP) { stop_firewall(); @@ -2218,6 +2206,12 @@ TOP: goto CLEAR; } + if (strcmp(service, "arpbind") == 0) { + if (action & A_STOP) stop_arpbind(); + if (action & A_START) start_arpbind(); + goto CLEAR; + } + if (strcmp(service, "qos") == 0) { if (action & A_STOP) { stop_qos(); @@ -2241,12 +2235,6 @@ TOP: goto CLEAR; } - if (strcmp(service, "arpbind") == 0) { - if (action & A_STOP) stop_arpbind(); - if (action & A_START) stop_arpbind(); - goto CLEAR; - } - if (strcmp(service, "upnp") == 0) { if (action & A_STOP) { stop_upnp(); -- 2.11.4.GIT