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