]> git.pld-linux.org Git - packages/kernel.git/blob - kernel-ipt_account.patch
- up to 2.6.17.28
[packages/kernel.git] / kernel-ipt_account.patch
1 diff -uNrp linux/net/ipv4/netfilter/ipt_account.c linux/net/ipv4/netfilter/ipt_account.c
2 --- linux/net/ipv4/netfilter/ipt_account.c      1970-01-01 01:00:00.000000000 +0100
3 +++ linux/net/ipv4/netfilter/ipt_account.c      2007-08-04 16:22:15.000000000 +0200
4 @@ -0,0 +1,973 @@
5 +/* Copyright (c) 2004-2007 Piotr 'QuakeR' Gasidlo <quaker@barbara.eu.org>
6 + *
7 + * This program is free software; you can redistribute it and/or modify
8 + * it under the terms of the GNU General Public License version 2 as
9 + * published by the Free Software Foundation.
10 + */
11 +
12 +#include <linux/version.h>
13 +#include <linux/module.h>
14 +#include <linux/skbuff.h>
15 +#include <linux/vmalloc.h>
16 +#include <linux/proc_fs.h>
17 +#include <linux/seq_file.h>
18 +#include <linux/time.h>
19 +#include <linux/ip.h>
20 +#include <linux/in.h>
21 +
22 +#define IPT_ACCOUNT_VERSION "0.1.21"
23 +
24 +//#define DEBUG_IPT_ACCOUNT
25 +
26 +MODULE_AUTHOR("Piotr Gasidlo <quaker@barbara.eu.org>");
27 +MODULE_DESCRIPTION("Traffic accounting module");
28 +MODULE_LICENSE("GPL");
29 +
30 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)  
31 +#include <linux/netfilter/x_tables.h>
32 +#else
33 +#include <linux/netfilter_ipv4/ip_tables.h>
34 +#endif
35 +#include <linux/netfilter_ipv4/ipt_account.h>
36 +
37 +/* defaults, can be overriden */
38 +static unsigned int netmask = 16; /* Safe netmask, if you try to create table
39 +                                     for larger netblock you will get error. 
40 +                                     Increase by command line only when you
41 +                                     known what are you doing. */
42 +
43 +#ifdef DEBUG_IPT_ACCOUNT
44 +static int debug = 0;
45 +#endif
46 +module_param(netmask, uint, 0400);
47 +
48 +MODULE_PARM_DESC(netmask,"maximum *save* netmask");
49 +#ifdef DEBUG_IPT_ACCOUNT
50 +module_param(debug, bool, 0600);
51 +MODULE_PARM_DESC(debug,"enable debugging output");
52 +#endif
53 +
54 +/* structure with statistics counter, used when table is created without --ashort switch */
55 +struct t_ipt_account_stat_long {
56 +  u_int64_t b_all, b_tcp, b_udp, b_icmp, b_other;
57 +  u_int64_t p_all, p_tcp, p_udp, p_icmp, p_other;
58 +};
59 +
60 +/* same as above, for tables created with --ashort switch */
61 +struct t_ipt_account_stat_short {
62 +  u_int64_t b_all;
63 +  u_int64_t p_all;
64 +};
65 +
66 +/* structure holding to/from statistics for single ip when table is created without --ashort switch */
67 +struct t_ipt_account_stats_long {
68 +  struct t_ipt_account_stat_long src, dst;
69 +  struct timespec time; /* time, when statistics was last modified */
70 +};
71 +
72 +/* same as above, for tables created with --ashort switch */
73 +struct t_ipt_account_stats_short {
74 +  struct t_ipt_account_stat_short src, dst;
75 +  struct timespec time;
76 +};
77 +
78 +/* defines for "show" table option */
79 +#define SHOW_ANY 0
80 +#define SHOW_SRC 1
81 +#define SHOW_DST 2
82 +#define SHOW_SRC_OR_DST 3
83 +#define SHOW_SRC_AND_DST 4
84 +
85 +/* structure describing single table */
86 +struct t_ipt_account_table {
87 +  struct list_head list;
88 +  atomic_t use; /* use counter, the number of rules which points to this table */
89 +
90 +  char name[IPT_ACCOUNT_NAME_LEN + 1]; /* table name ( = filename in /proc/net/ipt_account/) */
91 +  u_int32_t network, netmask, count; /* network/netmask/hosts count coverted by table */
92 +
93 +  int shortlisting:1; /* gather only total statistics (set for tables created with --ashort switch) */
94 +  int timesrc:1; /* update time when accounting outgoing traffic */
95 +  int timedst:1; /* update time when accounting incomming traffic */
96 +  int resetonread:1; /* reset statistics after reading it via proc */
97 +  int show; /* show with entries */
98 +
99 +  /* FIXME: why int show:3 results in 'warning: comparison is always 0 due to width of bit-field' in ipt_account_seq_show
100 +   * gcc -v: gcc version 3.4.6 */
101 +  
102 +  union { /* statistics for each ip in network/netmask */
103 +    struct t_ipt_account_stats_long *l;
104 +    struct t_ipt_account_stats_short *s;
105 +  } stats;
106 +  rwlock_t stats_lock; /* lock, to assure that above union can be safely modified */
107 +
108 +  struct proc_dir_entry *pde; /* handle to proc entry */
109 +};
110 +
111 +static LIST_HEAD(ipt_account_tables);
112 +static rwlock_t ipt_account_lock = RW_LOCK_UNLOCKED; /* lock, to assure that table list can be safely modified */
113 +static DECLARE_MUTEX(ipt_account_mutex); /* additional checkentry protection */
114 +
115 +static struct file_operations ipt_account_proc_fops;
116 +static struct proc_dir_entry *ipt_account_procdir;
117 +
118 +/*
119 + * Function creates new table and inserts it into linked list.
120 + */
121 +static struct t_ipt_account_table *
122 +ipt_account_table_init(struct t_ipt_account_info *info)
123 +{ 
124 +  struct t_ipt_account_table *table;
125 +
126 +#ifdef DEBUG_IPT_ACCOUNT  
127 +  if (debug) printk(KERN_DEBUG "ipt_account [ipt_account_table_init]: name = %s\n", info->name);
128 +#endif
129 +
130 +  /*
131 +   * Allocate memory for table.
132 +   */
133 +  table = vmalloc(sizeof(struct t_ipt_account_table));
134 +  if (!table) {
135 +    printk(KERN_ERR "ipt_account [ipt_account_table_init]: table = vmalloc(sizeof(struct t_ipt_account_table)) failed.\n");
136 +    goto cleanup_none;
137 +  }
138 +  memset(table, 0, sizeof(struct t_ipt_account_table));
139 +
140 +  /*
141 +   * Table attributes.
142 +   */
143 +  strncpy(table->name, info->name, IPT_ACCOUNT_NAME_LEN); 
144 +  table->name[IPT_ACCOUNT_NAME_LEN] = '\0';
145 +
146 +  table->network = info->network;
147 +  table->netmask = info->netmask;
148 +  table->count = (0xffffffff ^ table->netmask) + 1;
149 +  
150 +  /*
151 +   * Table properties.
152 +   */
153 +  table->shortlisting = info->shortlisting;
154 +  table->timesrc = 1;
155 +  table->timedst = 1;
156 +  table->resetonread = 0; 
157 +  table->show = SHOW_ANY;
158 +
159 +  /*
160 +   * Initialize use counter.
161 +   */
162 +  atomic_set(&table->use, 1);
163 +
164 +  /*
165 +   * Allocate memory for statistic counters.
166 +   */
167 +  if (table->shortlisting) {
168 +    table->stats.s = vmalloc(sizeof(struct t_ipt_account_stats_short) * table->count);
169 +    if (!table->stats.s) {
170 +      printk(KERN_ERR "ipt_account [ipt_account_table_init]: table->stats.s = vmalloc(sizeof(struct t_ipt_account_stats_short) * table->count) failed.\n");
171 +      goto cleanup_table;
172 +    }
173 +    memset(table->stats.s, 0, sizeof(struct t_ipt_account_stats_short) * table->count);
174 +  } else {
175 +    table->stats.l = vmalloc(sizeof(struct t_ipt_account_stats_long) * table->count);
176 +    if (!table->stats.l) {
177 +      printk(KERN_ERR "ipt_account [ipt_account_table_init]: table->stats.l = vmalloc(sizeof(struct t_ipt_account_stats_long) * table->count) failed.\n");
178 +      goto cleanup_table;
179 +    }
180 +    memset(table->stats.l, 0, sizeof(struct t_ipt_account_stats_long) * table->count);
181 +  }
182 +  
183 +  /*
184 +   * Reset locks.
185 +   */
186 +  table->stats_lock = RW_LOCK_UNLOCKED;
187 +  
188 +  /*
189 +   * Create /proc/ipt_account/name entry.
190 +   */
191 +  table->pde = create_proc_entry(table->name, S_IWUSR | S_IRUSR, ipt_account_procdir);
192 +  if (!table->pde) {
193 +    goto cleanup_stats;
194 +  }
195 +  table->pde->proc_fops = &ipt_account_proc_fops;
196 +  table->pde->data = table;
197 +  
198 +  /*
199 +   * Insert table into list.
200 +   */
201 +  write_lock_bh(&ipt_account_lock);
202 +  list_add(&table->list, &ipt_account_tables);
203 +  write_unlock_bh(&ipt_account_lock);
204 +  
205 +  return table;
206 +
207 +  /*
208 +   * If something goes wrong we end here.
209 +   */
210 +cleanup_stats:
211 +  if (table->shortlisting)
212 +    vfree(table->stats.s);
213 +  else
214 +    vfree(table->stats.l);
215 +  
216 +cleanup_table:
217 +  vfree(table);
218 +cleanup_none:
219 +  return NULL;
220 +  
221 +}
222 +
223 +/*
224 + * Function destroys table. Table *must* be already unlinked.
225 + */
226 +static void
227 +ipt_account_table_destroy(struct t_ipt_account_table *table)
228 +{
229 +#ifdef DEBUG_IPT_ACCOUNT  
230 +  if (debug) printk(KERN_DEBUG "ipt_account [ipt_account_table_destory]: name = %s\n", table->name);
231 +#endif  
232 +  remove_proc_entry(table->pde->name, table->pde->parent);
233 +  if (table->shortlisting)
234 +    vfree(table->stats.s);
235 +  else
236 +    vfree(table->stats.l);
237 +  vfree(table);
238 +}
239 +
240 +/*
241 + * Function increments use counter for table.
242 + */
243 +static inline void
244 +ipt_account_table_get(struct t_ipt_account_table *table) 
245 +{
246 +#ifdef DEBUG_IPT_ACCOUNT  
247 +  if (debug) printk(KERN_DEBUG "ipt_account [ipt_account_table_get]: name = %s\n", table->name);
248 +#endif    
249 +  atomic_inc(&table->use);
250 +}
251 +
252 +/*
253 + * Function decrements use counter for table. If use counter drops to zero,
254 + * table is removed from linked list and destroyed.
255 + */
256 +static inline void
257 +ipt_account_table_put(struct t_ipt_account_table *table) 
258 +{
259 +#ifdef DEBUG_IPT_ACCOUNT  
260 +  if (debug) printk(KERN_DEBUG "ipt_account [ipt_account_table_put]: name = %s\n", table->name);  
261 +#endif  
262 +  if (atomic_dec_and_test(&table->use)) {
263 +    write_lock_bh(&ipt_account_lock);
264 +    list_del(&table->list);
265 +    write_unlock_bh(&ipt_account_lock);
266 +    ipt_account_table_destroy(table);
267 +  }
268 +}
269 +
270 +/*
271 + * Helper function, which returns a structure pointer to a table with
272 + * specified name.
273 + */
274 +static struct t_ipt_account_table *
275 +__ipt_account_table_find(char *name) 
276 +{
277 +  struct list_head *pos;
278 +  list_for_each(pos, &ipt_account_tables) {
279 +    struct t_ipt_account_table *table = list_entry(pos,
280 +        struct t_ipt_account_table, list);
281 +    if (!strncmp(table->name, name, IPT_ACCOUNT_NAME_LEN))
282 +      return table;
283 +  }
284 +  return NULL;
285 +}
286 +
287 +/*
288 + * Function, which returns a structure pointer to a table with
289 + * specified name. When such table is found its use coutner
290 + * is incremented.
291 + */
292 +static inline struct t_ipt_account_table *
293 +ipt_account_table_find_get(char *name) 
294 +{
295 +  struct t_ipt_account_table *table;
296 +  
297 +#ifdef DEBUG_IPT_ACCOUNT  
298 +  if (debug) printk(KERN_DEBUG "ipt_account [ipt_account_table_find_get]: name = %s\n", name);  
299 +#endif  
300 +  read_lock_bh(&ipt_account_lock);
301 +  table = __ipt_account_table_find(name);
302 +  if (!table) {
303 +    read_unlock_bh(&ipt_account_lock);
304 +    return NULL;
305 +  }
306 +  atomic_inc(&table->use);
307 +  read_unlock_bh(&ipt_account_lock);
308 +  return table;
309 +} 
310 +
311 +/*
312 + * Helper function, with updates statistics for specified IP. It's only
313 + * used for tables created without --ashort switch.
314 + */
315 +static inline void
316 +__account_long(struct t_ipt_account_stat_long *stat, const struct sk_buff *skb) 
317 +{
318 +  stat->b_all += skb->len;
319 +  stat->p_all++;
320 +  
321 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)  
322 +  switch (ip_hdr(skb)->protocol) {
323 +#else
324 +  switch (skb->nh.iph->protocol) {
325 +#endif    
326 +    case IPPROTO_TCP:
327 +      stat->b_tcp += skb->len;
328 +      stat->p_tcp++;
329 +      break;
330 +    case IPPROTO_UDP:
331 +      stat->b_udp += skb->len;
332 +      stat->p_udp++;
333 +      break;
334 +    case IPPROTO_ICMP:
335 +      stat->b_icmp += skb->len;
336 +      stat->p_icmp++;
337 +      break;
338 +    default:
339 +      stat->b_other += skb->len;
340 +      stat->p_other++;
341 +  }
342 +}
343 +
344 +/*
345 + * Same as above, but used for tables created with --ashort switch.
346 + */
347 +static inline void
348 +__account_short(struct t_ipt_account_stat_short *stat, const struct sk_buff *skb)
349 +{
350 +  stat->b_all += skb->len;
351 +  stat->p_all++;
352 +}
353 +
354 +/*
355 + * Match function. Here we do accounting stuff.
356 + */
357 +static bool
358 +match(const struct sk_buff *skb,
359 +      const struct net_device *in,
360 +      const struct net_device *out,
361 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
362 +      const struct xt_match *match,
363 +#endif            
364 +      const void *matchinfo,
365 +      int offset,
366 +      unsigned int protoff,
367 +      bool *hotdrop)
368 +{
369 +  struct t_ipt_account_info *info = (struct t_ipt_account_info *)matchinfo;
370 +  struct t_ipt_account_table *table = info->table;
371 +  u_int32_t address;  
372 +  /* Get current time. */
373 +  struct timespec now = CURRENT_TIME_SEC;
374 +  /* Default we assume no match. */
375 +  bool ret = false;
376 +    
377 +#ifdef DEBUG_IPT_ACCOUNT  
378 +  if (debug) printk(KERN_DEBUG "ipt_account [match]: name = %s\n", table->name);
379 +#endif  
380 +  /* Check whether traffic from source ip address ... */
381 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)  
382 +  address = ntohl(ip_hdr(skb)->saddr);
383 +#else
384 +  address = ntohl(skb->nh.iph->saddr);
385 +#endif  
386 +  /* ... is being accounted by this table. */ 
387 +  if (address && ((u_int32_t)(address & table->netmask) == (u_int32_t)table->network)) {    
388 +    write_lock_bh(&table->stats_lock);
389 +    /* Yes, account this packet. */
390 +#ifdef DEBUG_IPT_ACCOUNT  
391 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)  
392 +    if (debug) printk(KERN_DEBUG "ipt_account: [match]: accounting packet src = %u.%u.%u.%u, proto = %u.\n", HIPQUAD(address), ip_hdr(skb)->protocol);
393 +#else
394 +    if (debug) printk(KERN_DEBUG "ipt_account: [match]: accounting packet src = %u.%u.%u.%u, proto = %u.\n", HIPQUAD(address), skb->nh.iph->protocol);
395 +#endif  
396 +#endif  
397 +    /* Update counters this host. */
398 +    if (!table->shortlisting) {
399 +      __account_long(&table->stats.l[address - table->network].src, skb);
400 +      if (table->timesrc)
401 +        table->stats.l[address - table->network].time = now;
402 +      /* Update also counters for all hosts in this table (network address) */
403 +      if (table->count > 1) {
404 +        __account_long(&table->stats.l[0].src, skb);
405 +        table->stats.l[0].time = now;
406 +      }
407 +    } else {
408 +      __account_short(&table->stats.s[address - table->network].src, skb);
409 +      if (table->timedst)
410 +        table->stats.s[address - table->network].time = now;
411 +      if (table->count > 1) {
412 +        __account_short(&table->stats.s[0].src, skb);
413 +        table->stats.s[0].time = now;
414 +      }
415 +    }
416 +    write_unlock_bh(&table->stats_lock);
417 +    /* Yes, it's a match. */
418 +    ret = true;
419 +  }
420 +  
421 +  /* Do the same thing with destination ip address. */
422 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)  
423 +  address = ntohl(ip_hdr(skb)->daddr);
424 +#else
425 +  address = ntohl(skb->nh.iph->daddr);
426 +#endif  
427 +  if (address && ((u_int32_t)(address & table->netmask) == (u_int32_t)table->network)) {
428 +    write_lock_bh(&table->stats_lock);
429 +#ifdef DEBUG_IPT_ACCOUNT 
430 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)  
431 +    if (debug) printk(KERN_DEBUG "ipt_account: [match]: accounting packet dst = %u.%u.%u.%u, proto = %u.\n", HIPQUAD(address), ip_hdr(skb)->protocol);
432 +#else    
433 +    if (debug) printk(KERN_DEBUG "ipt_account: [match]: accounting packet dst = %u.%u.%u.%u, proto = %u.\n", HIPQUAD(address), skb->nh.iph->protocol);
434 +#endif  
435 +#endif    
436 +    if (!table->shortlisting) {
437 +      __account_long(&table->stats.l[address - table->network].dst, skb);
438 +      table->stats.l[address - table->network].time = now;
439 +      if (table->count > 1) {
440 +        __account_long(&table->stats.l[0].dst, skb);
441 +        table->stats.l[0].time = now;
442 +      }
443 +    } else {
444 +      __account_short(&table->stats.s[address - table->network].dst, skb);
445 +      table->stats.s[address - table->network].time = now;
446 +      if (table->count > 1) {
447 +        __account_short(&table->stats.s[0].dst, skb);
448 +        table->stats.s[0].time = now;
449 +      }
450 +    }
451 +    write_unlock_bh(&table->stats_lock);
452 +    ret = true;
453 +  }
454 +  
455 +  return ret;
456 +}
457 +
458 +/*
459 + * Checkentry function.
460 + */
461 +static bool
462 +checkentry(const char *tablename,
463 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)    
464 +     const void *ip,
465 +#else
466 +     const struct ipt_entry *ip,
467 +#endif
468 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)     
469 +     const struct xt_match *match,
470 +#endif     
471 +     void *matchinfo,
472 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
473 +     unsigned int matchsize,
474 +#endif     
475 +     unsigned int hook_mask)
476 +{
477 +  struct t_ipt_account_info *info = matchinfo;
478 +  struct t_ipt_account_table *table;
479 +
480 +#ifdef DEBUG_IPT_ACCOUNT  
481 +  if (debug) printk(KERN_DEBUG "ipt_account [checkentry]: name = %s\n", info->name);
482 +#endif  
483 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
484 +  if (matchsize != IPT_ALIGN(sizeof(struct t_ipt_account_info))) {
485 +#ifdef DEBUG_IPT_ACCOUNT  
486 +    if (debug) printk(KERN_DEBUG "ipt_account [checkentry]: matchsize %u != %u\n", matchsize, IPT_ALIGN(sizeof(struct t_ipt_account_info)));
487 +#endif    
488 +    return false;
489 +  }
490 +#endif
491 +
492 +  /* 
493 +   * Sanity checks. 
494 +   */
495 +  if (info->netmask < ((~0L << (32 - netmask)) & 0xffffffff)) {
496 +    printk(KERN_ERR "ipt_account[checkentry]: too big netmask (increase module 'netmask' parameter).\n");
497 +    return false;
498 +  }
499 +  if ((info->network & info->netmask) != info->network) {
500 +    printk(KERN_ERR "ipt_account[checkentry]: wrong network/netmask.\n");
501 +    return false;
502 +  }
503 +  if (info->name[0] == '\0') {
504 +    printk(KERN_ERR "ipt_account[checkentry]: wrong table name.\n");
505 +    return false;
506 +  }
507 +
508 +  /*
509 +   * We got new rule. Try to find table with the same name as given in info structure.
510 +   * Mutex magic based on xt_hashlimit.c.
511 +   */
512 +  down(&ipt_account_mutex);
513 +  table = ipt_account_table_find_get(info->name);
514 +  if (table) {
515 +    if (info->table != NULL) {
516 +      if (info->table != table) {
517 +        printk(KERN_ERR "ipt_account[checkentry]: reloaded rule has invalid table pointer.\n");
518 +        up(&ipt_account_mutex);
519 +        return false;
520 +      }
521 +      up(&ipt_account_mutex);
522 +      return true;
523 +    } else {
524 +#ifdef DEBUG_IPT_ACCOUNT  
525 +      if (debug) printk(KERN_DEBUG "ipt_account [checkentry]: table found, checking.\n");
526 +#endif  
527 +      /* 
528 +       * Table exists, but whether rule network/netmask/shortlisting matches 
529 +       * table network/netmask/shortlisting. Failure on missmatch. 
530 +       */   
531 +      if (table->network != info->network || table->netmask != info->netmask || table->shortlisting != info->shortlisting) {
532 +        printk(KERN_ERR "ipt_account [checkentry]: table found, rule network/netmask/shortlisting not match table network/netmask/shortlisting.\n");
533 +        /*
534 +         * Remember to release table usage counter.
535 +         */
536 +        ipt_account_table_put(table);
537 +        up(&ipt_account_mutex);
538 +        return false;
539 +      }
540 +#ifdef DEBUG_IPT_ACCOUNT  
541 +      if (debug) printk(KERN_DEBUG "ipt_account [checkentry]: table found, reusing.\n");
542 +#endif  
543 +      /*
544 +       * Link rule with table.
545 +       */ 
546 +      info->table = table;
547 +    }
548 +  } else {
549 +#ifdef DEBUG_IPT_ACCOUNT  
550 +    if (debug) printk(KERN_DEBUG "ipt_account [checkentry]: table not found, creating new one.\n");
551 +#endif  
552 +    /*
553 +     * Table not exist, create new one.
554 +     */
555 +    info->table = table = ipt_account_table_init(info);
556 +    if (!table) {
557 +      up(&ipt_account_mutex);
558 +      return false;
559 +    }
560 +  }
561 +  up(&ipt_account_mutex);
562 +  return true;
563 +}
564 +
565 +/*
566 + * Destroy function.
567 + */
568 +static void
569 +destroy(
570 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)    
571 +    const struct xt_match *match,
572 +#endif    
573 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)
574 +    void *matchinfo
575 +#else
576 +    void *matchinfo,
577 +    unsigned int matchsize
578 +#endif    
579 +)
580 +{
581 +  struct t_ipt_account_info *info = matchinfo;
582 +  
583 +#ifdef DEBUG_IPT_ACCOUNT  
584 +  if (debug) printk(KERN_DEBUG "ipt_account [destroy]: name = %s\n", info->name);
585 +#endif  
586 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
587 +  if (matchsize != IPT_ALIGN(sizeof(struct t_ipt_account_info))) {
588 +#ifdef DEBUG_IPT_ACCOUNT  
589 +    if (debug) printk(KERN_DEBUG "ipt_account [checkentry]: matchsize %u != %u\n", matchsize, IPT_ALIGN(sizeof(struct t_ipt_account_info)));
590 +#endif    
591 +    return;
592 +  }
593 +#endif
594 +
595 +  /*
596 +   * Release table, by decreasing its usage counter. When
597 +   * counter hits zero, memory used by table structure is
598 +   * released and table is removed from list.
599 +   */
600 +  ipt_account_table_put(info->table);
601 +  return;
602 +}
603 +
604 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
605 +static struct xt_match account_match = { 
606 +#else
607 +static struct ipt_match account_match = { 
608 +#endif  
609 +  .name = "account", 
610 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
611 +  .family = AF_INET,
612 +#endif  
613 +  .match = &match, 
614 +  .checkentry = &checkentry, 
615 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
616 +  .matchsize = sizeof(struct t_ipt_account_info),
617 +#endif  
618 +  .destroy = &destroy, 
619 +  .me = THIS_MODULE
620 +};
621 +
622 +/*
623 + * Below functions (ipt_account_seq_start, ipt_account_seq_next, 
624 + * ipt_account_seq_stop, ipt_account_seq_show, ipt_account_proc_write) 
625 + * are used to implement proc stuff.
626 + */
627 +static void *ipt_account_seq_start(struct seq_file *sf, loff_t *pos)
628 +{
629 +  struct proc_dir_entry *pde = sf->private;
630 +  struct t_ipt_account_table *table = pde->data;
631 +  unsigned int *i;
632 +
633 +  if (table->resetonread) {
634 +    /* When we reset entries after read we must have exclusive lock. */
635 +    write_lock_bh(&table->stats_lock);
636 +  } else {
637 +    read_lock_bh(&table->stats_lock);
638 +  }
639 +  if (*pos >= table->count)
640 +    return NULL;
641 +  i = kmalloc(sizeof(unsigned int), GFP_ATOMIC);
642 +  if (!i)
643 +    return ERR_PTR(-ENOMEM);
644 +  *i = *pos;
645 +  return i;
646 +}
647 +
648 +static void *ipt_account_seq_next(struct seq_file *sf, void *v, loff_t *pos)
649 +{
650 +  struct proc_dir_entry *pde = sf->private;
651 +  struct t_ipt_account_table *table = pde->data;
652 +  unsigned int *i = (unsigned int *)v;
653 +
654 +  *pos = ++(*i);
655 +  if (*i >= table->count) {
656 +    kfree(v);
657 +    return NULL;
658 +  }
659 +  return i;
660 +}
661 +
662 +static void ipt_account_seq_stop(struct seq_file *sf, void *v)
663 +{
664 +  struct proc_dir_entry *pde = sf->private;
665 +  struct t_ipt_account_table *table = pde->data;
666 +  kfree(v);
667 +  if (table->resetonread) {   
668 +    write_unlock_bh(&table->stats_lock);
669 +  } else {
670 +    read_unlock_bh(&table->stats_lock);
671 +  }
672 +}
673 +
674 +static int ipt_account_seq_show(struct seq_file *sf, void *v)
675 +{
676 +  struct proc_dir_entry *pde = sf->private;
677 +  struct t_ipt_account_table *table = pde->data;
678 +  unsigned int *i = (unsigned int *)v;
679 +  
680 +  struct timespec now = CURRENT_TIME_SEC;
681 +  
682 +  u_int32_t address = table->network + *i;
683 +
684 +  if (!table->shortlisting) {
685 +    struct t_ipt_account_stats_long *l = &table->stats.l[*i];
686 +    /* Don't list rows not matching show requirements. */
687 +    if (
688 +        ((table->show == SHOW_SRC) && (l->src.p_all == 0)) ||
689 +        ((table->show == SHOW_DST) && (l->dst.p_all == 0)) ||
690 +        ((table->show == SHOW_SRC_OR_DST) && ((l->src.p_all == 0) && (l->dst.p_all == 0))) ||
691 +        ((table->show == SHOW_SRC_AND_DST) && ((l->src.p_all == 0) || (l->dst.p_all == 0)))
692 +       ) {
693 +      return 0;
694 +    }
695 +    seq_printf(sf,
696 +        "ip = %u.%u.%u.%u bytes_src = %llu %llu %llu %llu %llu packets_src = %llu %llu %llu %llu %llu bytes_dst = %llu %llu %llu %llu %llu packets_dst = %llu %llu %llu %llu %llu time = %lu\n",
697 +        HIPQUAD(address),
698 +        l->src.b_all,
699 +        l->src.b_tcp,
700 +        l->src.b_udp,
701 +        l->src.b_icmp,
702 +        l->src.b_other,
703 +        l->src.p_all,
704 +        l->src.p_tcp,
705 +        l->src.p_udp,
706 +        l->src.p_icmp,
707 +        l->src.p_other,
708 +        l->dst.b_all,
709 +        l->dst.b_tcp,
710 +        l->dst.b_udp,
711 +        l->dst.b_icmp,
712 +        l->dst.b_other,       
713 +        l->dst.p_all,
714 +        l->dst.p_tcp,
715 +        l->dst.p_udp,
716 +        l->dst.p_icmp,
717 +        l->dst.p_other,
718 +        now.tv_sec - l->time.tv_sec
719 +      );
720 +    if (table->resetonread)
721 +      memset(l, 0, sizeof(struct t_ipt_account_stats_long));
722 +    
723 +  } else {
724 +    struct t_ipt_account_stats_short *s = &table->stats.s[*i];
725 +    if (
726 +        ((table->show == SHOW_SRC) && (s->src.p_all == 0)) ||
727 +        ((table->show == SHOW_DST) && (s->dst.p_all == 0)) ||
728 +        ((table->show == SHOW_SRC_OR_DST) && ((s->src.p_all == 0) && (s->dst.p_all == 0))) ||
729 +        ((table->show == SHOW_SRC_AND_DST) && ((s->src.p_all == 0) || (s->dst.p_all == 0)))
730 +       ) {
731 +      return 0;
732 +    }
733 +    seq_printf(sf,
734 +        "ip = %u.%u.%u.%u bytes_src = %llu packets_src = %llu bytes_dst = %llu packets_dst = %llu time = %lu\n",
735 +        HIPQUAD(address),
736 +        s->src.b_all,
737 +        s->src.p_all,
738 +        s->dst.b_all,
739 +        s->dst.p_all,
740 +        now.tv_sec - s->time.tv_sec
741 +      );
742 +    if (table->resetonread)
743 +      memset(s, 0, sizeof(struct t_ipt_account_stats_short));
744 +  }
745 +
746 +  return 0;
747 +}
748 +
749 +static struct seq_operations ipt_account_seq_ops = {
750 +  .start = ipt_account_seq_start,
751 +  .next = ipt_account_seq_next,
752 +  .stop = ipt_account_seq_stop,
753 +  .show = ipt_account_seq_show
754 +};
755 +
756 +static ssize_t ipt_account_proc_write(struct file *file, const char __user *input, size_t size, loff_t *ofs)
757 +{
758 +  char buffer[1024];
759 +  struct proc_dir_entry *pde = PDE(file->f_dentry->d_inode);
760 +  struct t_ipt_account_table *table = pde->data;
761 +
762 +  u_int32_t o[4], ip;
763 +  struct t_ipt_account_stats_long l;
764 +  struct t_ipt_account_stats_short s;
765 +
766 +#ifdef DEBUG_IPT_ACCOUNT  
767 +  if (debug) printk(KERN_DEBUG "ipt_account [ipt_account_proc_write]: name = %s.\n", table->name);
768 +#endif  
769 +  if (copy_from_user(buffer, input, 1024))
770 +    return -EFAULT;
771 +  buffer[1023] = '\0';
772 +
773 +  if (!strncmp(buffer, "reset\n", 6)) {
774 +    /*
775 +     * User requested to clear all table. Ignorant, does
776 +     * he known how match time it took us to fill it? ;-)
777 +     */
778 +    write_lock_bh(&table->stats_lock);
779 +    if (table->shortlisting)
780 +      memset(table->stats.s, 0, sizeof(struct t_ipt_account_stats_short) * table->count);
781 +    else
782 +      memset(table->stats.l, 0, sizeof(struct t_ipt_account_stats_long) * table->count);
783 +    write_unlock_bh(&table->stats_lock);    
784 +  } else if (!strncmp(buffer, "reset-on-read=yes\n", 18)) {
785 +    /*
786 +     * We must be sure that ipt_account_seq_* is not running now. This option
787 +     * changes lock type which is taken in ipt_account_seq_{start|stop}. When
788 +     * we change this option without this lock, and ipt_account_seq_start is
789 +     * already run (but not ipt_account_seq_stop) there is possibility that
790 +     * we execute wrong "unlock" function.
791 +     */
792 +    write_lock_bh(&table->stats_lock);
793 +    table->resetonread = 1;
794 +    write_unlock_bh(&table->stats_lock);
795 +  } else if (!strncmp(buffer, "reset-on-read=no\n", 17)) {
796 +    write_lock_bh(&table->stats_lock);
797 +    table->resetonread = 0; 
798 +    write_unlock_bh(&table->stats_lock);
799 +  } else if (!strncmp(buffer, "reset-on-read\n", 14)) {
800 +    write_lock_bh(&table->stats_lock);
801 +    table->resetonread = 1;
802 +    write_unlock_bh(&table->stats_lock);
803 +  } else if (!strncmp(buffer, "show=any\n", 9)) {
804 +    /*
805 +     * Here we should lock but we don't have to. So we don't lock. We only get
806 +     * wrong results on already run ipt_account_seq_show, but we won't crush
807 +     * the system.
808 +     */
809 +    table->show = SHOW_ANY;
810 +  } else if (!strncmp(buffer, "show=src\n", 9)) {
811 +    table->show = SHOW_SRC;
812 +  } else if (!strncmp(buffer, "show=dst\n", 9)) {
813 +    table->show = SHOW_DST;
814 +  } else if (!strncmp(buffer, "show=src-or-dst\n", 16) || !strncmp(buffer, "show=dst-or-src\n", 16)) {
815 +    table->show = SHOW_SRC_OR_DST;
816 +  } else if (!strncmp(buffer, "show=src-and-dst\n", 17) || !strncmp(buffer, "show=dst-and-src\n", 17)) {
817 +    table->show = SHOW_SRC_AND_DST;
818 +  } else if (!strncmp(buffer, "time=any\n", 9)) {
819 +    table->timesrc = table->timedst = 1;
820 +  } else if (!strncmp(buffer, "time=src\n", 9)) {
821 +    table->timesrc = 1;
822 +    table->timedst = 0;
823 +  } else if (!strncmp(buffer, "time=dst\n", 9)) {
824 +    table->timesrc = 0;
825 +    table->timedst = 1;
826 +  } else if (!table->shortlisting && sscanf(buffer, "ip = %u.%u.%u.%u bytes_src = %llu %llu %llu %llu %llu packets_src = %llu %llu %llu %llu %llu bytes_dst = %llu %llu %llu %llu %llu packets_dst = %llu %llu %llu %llu %llu time = %lu",        
827 +        &o[0], &o[1], &o[2], &o[3],
828 +        &l.src.b_all, &l.src.b_tcp, &l.src.b_udp, &l.src.b_icmp, &l.src.b_other,
829 +        &l.src.p_all, &l.src.p_tcp, &l.src.p_udp, &l.src.p_icmp, &l.src.p_other,
830 +        &l.dst.b_all, &l.dst.b_tcp, &l.dst.b_udp, &l.dst.b_icmp, &l.dst.b_other,
831 +        &l.dst.p_all, &l.dst.p_tcp, &l.dst.p_udp, &l.dst.p_icmp, &l.dst.p_other,
832 +        &l.time.tv_sec) == 25 ) {
833 +    /*
834 +     * We got line formated like long listing row. We have to
835 +     * check, if IP is accounted by table. If so, we
836 +     * simply replace row with user's one.
837 +     */
838 +    ip = o[0] << 24 | o[1] << 16 | o[2] << 8 | o[3];
839 +    if ((u_int32_t)(ip & table->netmask) == (u_int32_t)table->network) {
840 +      /*
841 +       * Ignore user input time. Set current time.
842 +       */
843 +      l.time = CURRENT_TIME_SEC;
844 +      write_lock_bh(&table->stats_lock);
845 +      table->stats.l[ip - table->network] = l;
846 +      write_unlock_bh(&table->stats_lock);
847 +    }
848 +  } else if (table->shortlisting && sscanf(buffer, "ip = %u.%u.%u.%u bytes_src = %llu packets_src = %llu bytes_dst = %llu packets_dst = %llu time = %lu\n", 
849 +        &o[0], &o[1], &o[2], &o[3], 
850 +        &s.src.b_all, 
851 +        &s.src.p_all, 
852 +        &s.dst.b_all, 
853 +        &s.dst.p_all, 
854 +        &s.time.tv_sec) == 9) {   
855 +    /*
856 +     * We got line formated like short listing row. Do the
857 +     * same action like above.
858 +     */
859 +    ip = o[0] << 24 | o[1] << 16 | o[2] << 8 | o[3];    
860 +    if ((u_int32_t)(ip & table->netmask) == (u_int32_t)table->network) {
861 +      s.time = CURRENT_TIME_SEC;
862 +      write_lock_bh(&table->stats_lock);
863 +      table->stats.s[ip - table->network] = s;
864 +      write_unlock_bh(&table->stats_lock);
865 +    }
866 +  } else {
867 +    /*
868 +     * We don't understand what user have just wrote.
869 +     */
870 +    return -EIO;
871 +  }
872 +
873 +  return size;
874 +}
875 +
876 +static int ipt_account_proc_open(struct inode *inode, struct file *file)
877 +{
878 +  int ret = seq_open(file, &ipt_account_seq_ops);
879 +  if (!ret) {
880 +    struct seq_file *sf = file->private_data;
881 +    struct proc_dir_entry *pde = PDE(inode);
882 +    struct t_ipt_account_table *table = pde->data;
883 +    
884 +    sf->private = pde;
885 +
886 +    ipt_account_table_get(table);
887 +  }
888 +  return ret;
889 +}
890 +
891 +static int ipt_account_proc_release(struct inode *inode, struct file *file)
892 +{
893 +  struct proc_dir_entry *pde = PDE(inode);
894 +  struct t_ipt_account_table *table = pde->data;
895 +  int ret;
896 +
897 +  ret = seq_release(inode, file);
898 +
899 +  if (!ret)
900 +    ipt_account_table_put(table);
901 +  
902 +  return ret;
903 +}
904 +
905 +static struct file_operations ipt_account_proc_fops = {
906 +  .owner = THIS_MODULE,
907 +  .open = ipt_account_proc_open,
908 +  .read = seq_read,
909 +  .write = ipt_account_proc_write,
910 +  .llseek = seq_lseek,
911 +  .release = ipt_account_proc_release
912 +};
913 +
914 +/*
915 + * Module init function.
916 + */
917 +static int __init init(void)
918 +{
919 +  int ret = 0;
920 +
921 +  printk(KERN_INFO "ipt_account %s : Piotr Gasidlo <quaker@barbara.eu.org>, http://www.barbara.eu.org/~quaker/ipt_account/\n", IPT_ACCOUNT_VERSION);
922 +
923 +  /* Check module parameters. */
924 +  if (netmask > 32 || netmask < 0) {
925 +    printk(KERN_ERR "ipt_account[__init]: Wrong netmask given as parameter (%i). Valid is 32 to 0.\n", netmask);
926 +    ret = -EINVAL;
927 +    goto cleanup_none;
928 +  }
929 +  
930 +  /* Register match. */
931 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
932 +  if (xt_register_match(&account_match)) {
933 +#else    
934 +  if (ipt_register_match(&account_match)) {
935 +#endif  
936 +    ret = -EINVAL;
937 +    goto cleanup_none;
938 +  }
939 +
940 +  /* Create /proc/net/ipt_account/ entry. */
941 +  ipt_account_procdir = proc_mkdir("ipt_account", init_net.proc_net);
942 +  if (!ipt_account_procdir) {   
943 +    printk(KERN_ERR "ipt_account [__init]: ipt_account_procdir = proc_mkdir(\"ipt_account\", init_net.proc_net) failed.\n");
944 +    ret = -ENOMEM;
945 +    goto cleanup_match;
946 +  }
947 +  
948 +  return ret;
949 +
950 +  /* If something goes wrong we end here. */
951 +cleanup_match:
952 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
953 +  xt_unregister_match(&account_match);
954 +#else  
955 +  ipt_unregister_match(&account_match);
956 +#endif  
957 +cleanup_none:
958 +  return ret;
959 +}
960 +
961 +/*
962 + * Module exit function.
963 + */
964 +static void __exit fini(void)
965 +{
966 +  /* Remove /proc/net/ipt_account/ */
967 +  remove_proc_entry(ipt_account_procdir->name, ipt_account_procdir->parent);  
968 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
969 +  xt_unregister_match(&account_match);
970 +#else
971 +  ipt_unregister_match(&account_match);
972 +#endif  
973 +}
974 +
975 +module_init(init);
976 +module_exit(fini);
977 +
978 diff -uNrp linux/include/linux/netfilter_ipv4/ipt_account.h linux/include/linux/netfilter_ipv4/ipt_account.h
979 --- linux/include/linux/netfilter_ipv4/ipt_account.h    1970-01-01 01:00:00.000000000 +0100
980 +++ linux/include/linux/netfilter_ipv4/ipt_account.h    2007-08-04 15:24:49.000000000 +0200
981 @@ -0,0 +1,24 @@
982 +/* Copyright (c) 2004-2007 Piotr 'QuakeR' Gasidlo <quaker@barbara.eu.org>
983 + *
984 + * This program is free software; you can redistribute it and/or modify
985 + * it under the terms of the GNU General Public License version 2 as
986 + * published by the Free Software Foundation.
987 + */
988 +
989 +#ifndef _IPT_ACCOUNT_H_
990 +#define _IPT_ACCOUNT_H_
991 +
992 +#define IPT_ACCOUNT_NAME_LEN 64
993 +
994 +struct t_ipt_account_table;
995 +
996 +struct t_ipt_account_info {
997 +  char name[IPT_ACCOUNT_NAME_LEN + 1];
998 +  u_int32_t network, netmask;
999 +  int shortlisting:1;
1000 +  /* pointer to the table for fast matching */
1001 +  struct t_ipt_account_table *table;
1002 +};
1003 +
1004 +#endif /* _IPT_ACCOUNT_H */
1005 +
1006 diff -uNrp linux/net/ipv4/netfilter/Makefile.a linux/net/ipv4/netfilter/Makefile.b
1007 --- linux/net/ipv4/netfilter/Makefile   1971-01-01 01:00:00.000000000 +0100
1008 +++ linux/net/ipv4/netfilter/Makefile   2007-08-15 13:23:25.375304000 +0200
1009 @@ -0,0 +0,1 @@
1010 +obj-$(CONFIG_IP_NF_MATCH_ACCOUNT) += ipt_account.o
1011 diff -Nur linux/net/ipv4/netfilter/Kconfig linux/net/ipv4/netfilter/Kconfig
1012 --- linux/net/ipv4/netfilter/Kconfig    2006-05-02 23:38:44.000000000 +0200
1013 +++ linux/net/ipv4/netfilter/Kconfig    2006-05-04 11:23:02.000000000 +0200
1014 @@ -606,5 +606,51 @@
1015           Allows altering the ARP packet payload: source and destination
1016           hardware and network addresses.
1017  
1018 +config IP_NF_MATCH_ACCOUNT
1019 +       tristate "account match support"
1020 +       depends on IP_NF_IPTABLES && PROC_FS
1021 +       help
1022 +         This match is used for accounting traffic for all hosts in
1023 +         defined network/netmask. 
1024 +         
1025 +         Features:
1026 +         - long (one counter per protocol TCP/UDP/IMCP/Other) and short statistics
1027 +         - one iptables rule for all hosts in network/netmask
1028 +         - loading/saving counters (by reading/writting to procfs entries)
1029 +         
1030 +         Example usage:
1031 +         
1032 +         account traffic for/to 192.168.0.0/24 network into table mynetwork:
1033 +         
1034 +         # iptables -A FORWARD -m account --aname mynetwork --aaddr 192.168.0.0/24
1035 +         
1036 +         account traffic for/to WWW serwer for 192.168.0.0/24 network into table 
1037 +         mywwwserver:
1038 +         
1039 +         # iptables -A INPUT -p tcp --dport 80 
1040 +           -m account --aname mywwwserver --aaddr 192.168.0.0/24 --ashort
1041 +         # iptables -A OUTPUT -p tcp --sport 80
1042 +           -m account --aname mywwwserver --aaddr 192.168.0.0/24 --ashort    
1043 +         
1044 +         read counters:
1045 +         
1046 +         # cat /proc/net/ipt_account/mynetwork
1047 +         # cat /proc/net/ipt_account/mywwwserver
1048 +         
1049 +         set counters:
1050 +         
1051 +         # echo "ip = 192.168.0.1 packets_src = 0" > /proc/net/ipt_account/mywwserver
1052 +         
1053 +         Webpage: 
1054 +           http://www.barbara.eu.org/~quaker/ipt_account/
1055 +
1056 +config IP_NF_MATCH_ACCOUNT_DEBUG
1057 +       bool "account debugging output"
1058 +       depends on IP_NF_MATCH_ACCOUNT
1059 +       help
1060 +         Say Y to get lots of debugging output.
1061 +         
1062 +
1063 +
1064  endmenu
1065  
This page took 0.168921 seconds and 3 git commands to generate.