SOURCES (LINUX_2_6): kernel-ipt_account.patch (NEW) - based on htt...
zbyniu
zbyniu at pld-linux.org
Thu Aug 16 00:05:18 CEST 2007
Author: zbyniu Date: Wed Aug 15 22:05:18 2007 GMT
Module: SOURCES Tag: LINUX_2_6
---- Log message:
- based on http://www.svn.barbara.eu.org/ipt_account/attachment/wiki/Software/ipt_account-0.1.21-20070804164729.tar.gz
---- Files affected:
SOURCES:
kernel-ipt_account.patch (NONE -> 1.1.2.1) (NEW)
---- Diffs:
================================================================
Index: SOURCES/kernel-ipt_account.patch
diff -u /dev/null SOURCES/kernel-ipt_account.patch:1.1.2.1
--- /dev/null Thu Aug 16 00:05:18 2007
+++ SOURCES/kernel-ipt_account.patch Thu Aug 16 00:05:13 2007
@@ -0,0 +1,1016 @@
+diff -uNrp linux/net/ipv4/netfilter/ipt_account.c linux/net/ipv4/netfilter/ipt_account.c
+--- linux/net/ipv4/netfilter/ipt_account.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/net/ipv4/netfilter/ipt_account.c 2007-08-04 16:22:15.000000000 +0200
+@@ -0,0 +1,973 @@
++/* Copyright (c) 2004-2007 Piotr 'QuakeR' Gasidlo <quaker at barbara.eu.org>
++ *
++ * 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 <linux/version.h>
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/vmalloc.h>
++#include <linux/proc_fs.h>
++#include <linux/seq_file.h>
++#include <linux/time.h>
++#include <linux/ip.h>
++#include <linux/in.h>
++
++#define IPT_ACCOUNT_VERSION "0.1.21"
++
++//#define DEBUG_IPT_ACCOUNT
++
++MODULE_AUTHOR("Piotr Gasidlo <quaker at barbara.eu.org>");
++MODULE_DESCRIPTION("Traffic accounting module");
++MODULE_LICENSE("GPL");
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
++#include <linux/netfilter/x_tables.h>
++#else
++#include <linux/netfilter_ipv4/ip_tables.h>
++#endif
++#include <linux/netfilter_ipv4/ipt_account.h>
++
++/* 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_param(netmask, uint, 0400);
++
++MODULE_PARM_DESC(netmask,"maximum *save* netmask");
++#ifdef DEBUG_IPT_ACCOUNT
++module_param(debug, bool, 0600);
++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;
++};
++
++/* defines for "show" table option */
++#define SHOW_ANY 0
++#define SHOW_SRC 1
++#define SHOW_DST 2
++#define SHOW_SRC_OR_DST 3
++#define SHOW_SRC_AND_DST 4
++
++/* 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 */
++ int resetonread:1; /* reset statistics after reading it via proc */
++ int show; /* show with entries */
++
++ /* FIXME: why int show:3 results in 'warning: comparison is always 0 due to width of bit-field' in ipt_account_seq_show
++ * gcc -v: gcc version 3.4.6 */
++
++ 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 DEBUG_IPT_ACCOUNT
++ 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;
++ table->resetonread = 0;
++ table->show = SHOW_ANY;
++
++ /*
++ * 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 DEBUG_IPT_ACCOUNT
++ 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 DEBUG_IPT_ACCOUNT
++ 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 DEBUG_IPT_ACCOUNT
++ 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 DEBUG_IPT_ACCOUNT
++ 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++;
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
++ switch (ip_hdr(skb)->protocol) {
++#else
++ switch (skb->nh.iph->protocol) {
++#endif
++ 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,
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
++ const struct xt_match *match,
++#endif
++ const void *matchinfo,
++ int offset,
++ unsigned int protoff,
++ 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 = CURRENT_TIME_SEC;
++ /* Default we assume no match. */
++ int ret = 0;
++
++#ifdef DEBUG_IPT_ACCOUNT
++ if (debug) printk(KERN_DEBUG "ipt_account [match]: name = %s\n", table->name);
++#endif
++ /* Check whether traffic from source ip address ... */
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
++ address = ntohl(ip_hdr(skb)->saddr);
++#else
++ address = ntohl(skb->nh.iph->saddr);
++#endif
++ /* ... 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 DEBUG_IPT_ACCOUNT
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
++ if (debug) printk(KERN_DEBUG "ipt_account: [match]: accounting packet src = %u.%u.%u.%u, proto = %u.\n", HIPQUAD(address), ip_hdr(skb)->protocol);
++#else
++ 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
++#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. */
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
++ address = ntohl(ip_hdr(skb)->daddr);
++#else
++ address = ntohl(skb->nh.iph->daddr);
++#endif
++ if (address && ((u_int32_t)(address & table->netmask) == (u_int32_t)table->network)) {
++ write_lock_bh(&table->stats_lock);
++#ifdef DEBUG_IPT_ACCOUNT
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
++ if (debug) printk(KERN_DEBUG "ipt_account: [match]: accounting packet dst = %u.%u.%u.%u, proto = %u.\n", HIPQUAD(address), ip_hdr(skb)->protocol);
++#else
++ 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
++#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,
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
++ const void *ip,
++#else
++ const struct ipt_entry *ip,
++#endif
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
++ const struct xt_match *match,
++#endif
++ void *matchinfo,
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
++ unsigned int matchsize,
++#endif
++ unsigned int hook_mask)
++{
++ struct t_ipt_account_info *info = matchinfo;
++ struct t_ipt_account_table *table;
++
++#ifdef DEBUG_IPT_ACCOUNT
++ if (debug) printk(KERN_DEBUG "ipt_account [checkentry]: name = %s\n", info->name);
++#endif
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
++ if (matchsize != IPT_ALIGN(sizeof(struct t_ipt_account_info))) {
++#ifdef DEBUG_IPT_ACCOUNT
++ if (debug) printk(KERN_DEBUG "ipt_account [checkentry]: matchsize %u != %u\n", matchsize, IPT_ALIGN(sizeof(struct t_ipt_account_info)));
++#endif
++ return 0;
++ }
++#endif
++
++ /*
++ * 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 xt_hashlimit.c.
++ */
++ down(&ipt_account_mutex);
++ table = ipt_account_table_find_get(info->name);
++ if (table) {
++ if (info->table != NULL) {
++ if (info->table != table) {
++ 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 DEBUG_IPT_ACCOUNT
++ 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 DEBUG_IPT_ACCOUNT
++ if (debug) printk(KERN_DEBUG "ipt_account [checkentry]: table found, reusing.\n");
++#endif
++ /*
++ * Link rule with table.
++ */
++ info->table = table;
++ }
++ } else {
++#ifdef DEBUG_IPT_ACCOUNT
++ 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(
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
++ const struct xt_match *match,
++#endif
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)
++ void *matchinfo
++#else
++ void *matchinfo,
++ unsigned int matchsize
++#endif
++)
++{
++ struct t_ipt_account_info *info = matchinfo;
++
++#ifdef DEBUG_IPT_ACCOUNT
++ if (debug) printk(KERN_DEBUG "ipt_account [destroy]: name = %s\n", info->name);
++#endif
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
++ if (matchsize != IPT_ALIGN(sizeof(struct t_ipt_account_info))) {
++#ifdef DEBUG_IPT_ACCOUNT
++ if (debug) printk(KERN_DEBUG "ipt_account [checkentry]: matchsize %u != %u\n", matchsize, IPT_ALIGN(sizeof(struct t_ipt_account_info)));
++#endif
++ return;
<<Diff was trimmed, longer than 597 lines>>
More information about the pld-cvs-commit
mailing list