]>
Commit | Line | Data |
---|---|---|
1f0d84f2 | 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 | + */ | |
43b51ae9 | 357 | +static bool |
1f0d84f2 | 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, | |
43b51ae9 | 367 | + bool *hotdrop) |
1f0d84f2 | 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. */ | |
43b51ae9 | 375 | + bool ret = false; |
1f0d84f2 | 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. */ | |
43b51ae9 | 418 | + ret = true; |
1f0d84f2 | 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); | |
43b51ae9 | 452 | + ret = true; |
1f0d84f2 | 453 | + } |
454 | + | |
455 | + return ret; | |
456 | +} | |
457 | + | |
458 | +/* | |
459 | + * Checkentry function. | |
460 | + */ | |
43b51ae9 | 461 | +static bool |
1f0d84f2 | 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 | |
43b51ae9 | 488 | + return false; |
1f0d84f2 | 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"); | |
43b51ae9 | 497 | + return false; |
1f0d84f2 | 498 | + } |
499 | + if ((info->network & info->netmask) != info->network) { | |
500 | + printk(KERN_ERR "ipt_account[checkentry]: wrong network/netmask.\n"); | |
43b51ae9 | 501 | + return false; |
1f0d84f2 | 502 | + } |
503 | + if (info->name[0] == '\0') { | |
504 | + printk(KERN_ERR "ipt_account[checkentry]: wrong table name.\n"); | |
43b51ae9 | 505 | + return false; |
1f0d84f2 | 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); | |
43b51ae9 | 519 | + return false; |
1f0d84f2 | 520 | + } |
521 | + up(&ipt_account_mutex); | |
43b51ae9 | 522 | + return true; |
1f0d84f2 | 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); | |
43b51ae9 | 538 | + return false; |
1f0d84f2 | 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); | |
43b51ae9 | 558 | + return false; |
1f0d84f2 | 559 | + } |
560 | + } | |
561 | + up(&ipt_account_mutex); | |
43b51ae9 | 562 | + return true; |
1f0d84f2 | 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. */ | |
143a4708 | 941 | + ipt_account_procdir = proc_mkdir("ipt_account", init_net.proc_net); |
1f0d84f2 | 942 | + if (!ipt_account_procdir) { |
143a4708 | 943 | + printk(KERN_ERR "ipt_account [__init]: ipt_account_procdir = proc_mkdir(\"ipt_account\", init_net.proc_net) failed.\n"); |
1f0d84f2 | 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 | |
b1eea20b | 1007 | --- linux/net/ipv4/netfilter/Makefile 1971-01-01 01:00:00.000000000 +0100 |
1f0d84f2 | 1008 | +++ linux/net/ipv4/netfilter/Makefile 2007-08-15 13:23:25.375304000 +0200 |
a77c2279 | 1009 | @@ -0,0 +0,1 @@ |
1f0d84f2 | 1010 | +obj-$(CONFIG_IP_NF_MATCH_ACCOUNT) += ipt_account.o |
c973efff | 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 |