[kernel] generic-2.4: refresh patches
[openwrt/svn-archive/archive.git] / target / linux / generic-2.4 / patches / 610-netfilter_connbytes.patch
1 --- a/net/ipv4/netfilter/Config.in
2 +++ b/net/ipv4/netfilter/Config.in
3 @@ -11,6 +11,8 @@ if [ "$CONFIG_IP_NF_CONNTRACK" != "n" ];
4 dep_tristate ' Amanda protocol support' CONFIG_IP_NF_AMANDA $CONFIG_IP_NF_CONNTRACK
5 dep_tristate ' TFTP protocol support' CONFIG_IP_NF_TFTP $CONFIG_IP_NF_CONNTRACK
6 dep_tristate ' IRC protocol support' CONFIG_IP_NF_IRC $CONFIG_IP_NF_CONNTRACK
7 + dep_tristate ' Connection tracking flow accounting' CONFIG_IP_NF_CT_ACCT $CONFIG_IP_NF_CONNTRACK
8 + dep_tristate ' Connection byte counter support' CONFIG_IP_NF_MATCH_CONNBYTES $CONFIG_IP_NF_CT_ACCT $CONFIG_IP_NF_CONNTRACK $CONFIG_IP_NF_IPTABLES
9 dep_tristate ' GRE protocol support' CONFIG_IP_NF_CT_PROTO_GRE $CONFIG_IP_NF_CONNTRACK
10 dep_tristate ' PPTP protocol support' CONFIG_IP_NF_PPTP $CONFIG_IP_NF_CT_PROTO_GRE
11 fi
12 --- a/net/ipv4/netfilter/Makefile
13 +++ b/net/ipv4/netfilter/Makefile
14 @@ -106,6 +106,7 @@ obj-$(CONFIG_IP_NF_MATCH_LENGTH) += ipt_
15 obj-$(CONFIG_IP_NF_MATCH_TTL) += ipt_ttl.o
16 obj-$(CONFIG_IP_NF_MATCH_STATE) += ipt_state.o
17 obj-$(CONFIG_IP_NF_MATCH_CONNMARK) += ipt_connmark.o
18 +obj-$(CONFIG_IP_NF_MATCH_CONNBYTES) += ipt_connbytes.o
19 obj-$(CONFIG_IP_NF_MATCH_CONNTRACK) += ipt_conntrack.o
20 obj-$(CONFIG_IP_NF_MATCH_UNCLEAN) += ipt_unclean.o
21 obj-$(CONFIG_IP_NF_MATCH_STRING) += ipt_string.o
22 --- a/net/ipv4/netfilter/ip_conntrack_amanda.c
23 +++ b/net/ipv4/netfilter/ip_conntrack_amanda.c
24 @@ -75,7 +75,7 @@ static int help(const struct iphdr *iph,
25
26 /* increase the UDP timeout of the master connection as replies from
27 * Amanda clients to the server can be quite delayed */
28 - ip_ct_refresh(ct, master_timeout * HZ);
29 + ip_ct_refresh_acct(ct,ctinfo,NULL, master_timeout * HZ);
30
31 /* Search for "CONNECT " string */
32 do {
33 --- a/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
34 +++ b/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
35 @@ -211,7 +211,7 @@ static int tcp_packet(struct ip_conntrac
36 set_bit(IPS_ASSURED_BIT, &conntrack->status);
37
38 WRITE_UNLOCK(&tcp_lock);
39 - ip_ct_refresh(conntrack, *tcp_timeouts[newconntrack]);
40 + ip_ct_refresh_acct(conntrack,ctinfo,iph, *tcp_timeouts[newconntrack]);
41 }
42
43 return NF_ACCEPT;
44 --- a/net/ipv4/netfilter/ip_conntrack_proto_udp.c
45 +++ b/net/ipv4/netfilter/ip_conntrack_proto_udp.c
46 @@ -47,16 +47,16 @@ static unsigned int udp_print_conntrack(
47 /* Returns verdict for packet, and may modify conntracktype */
48 static int udp_packet(struct ip_conntrack *conntrack,
49 struct iphdr *iph, size_t len,
50 - enum ip_conntrack_info conntrackinfo)
51 + enum ip_conntrack_info ctinfo)
52 {
53 /* If we've seen traffic both ways, this is some kind of UDP
54 stream. Extend timeout. */
55 if (test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)) {
56 - ip_ct_refresh(conntrack, ip_ct_udp_timeout_stream);
57 + ip_ct_refresh_acct(conntrack,ctinfo,iph,ip_ct_udp_timeout_stream);
58 /* Also, more likely to be important, and not a probe */
59 set_bit(IPS_ASSURED_BIT, &conntrack->status);
60 } else
61 - ip_ct_refresh(conntrack, ip_ct_udp_timeout);
62 + ip_ct_refresh_acct(conntrack,ctinfo,iph, ip_ct_udp_timeout);
63
64 return NF_ACCEPT;
65 }
66 --- a/net/ipv4/netfilter/ip_conntrack_standalone.c
67 +++ b/net/ipv4/netfilter/ip_conntrack_standalone.c
68 @@ -79,6 +79,18 @@ print_expect(char *buffer, const struct
69 return len;
70 }
71
72 +#if defined(CONFIG_IP_NF_CT_ACCT) || \
73 + defined(CONFIG_IP_NF_CT_ACCT_MODULE)
74 +static unsigned int
75 +print_counters(char *buffer, struct ip_conntrack_counter *counter)
76 +{
77 + return sprintf(buffer, "packets=%llu bytes=%llu ",
78 + counter->packets, counter->bytes);
79 +}
80 +#else
81 +#define print_counters(x, y) 0
82 +#endif
83 +
84 static unsigned int
85 print_conntrack(char *buffer, struct ip_conntrack *conntrack)
86 {
87 @@ -98,11 +110,15 @@ print_conntrack(char *buffer, struct ip_
88 len += print_tuple(buffer + len,
89 &conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple,
90 proto);
91 + len += print_counters(buffer + len,
92 + &conntrack->counters[IP_CT_DIR_ORIGINAL]);
93 if (!(test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)))
94 len += sprintf(buffer + len, "[UNREPLIED] ");
95 len += print_tuple(buffer + len,
96 &conntrack->tuplehash[IP_CT_DIR_REPLY].tuple,
97 proto);
98 + len += print_counters(buffer + len,
99 + &conntrack->counters[IP_CT_DIR_REPLY]);
100 if (test_bit(IPS_ASSURED_BIT, &conntrack->status))
101 len += sprintf(buffer + len, "[ASSURED] ");
102 len += sprintf(buffer + len, "use=%u ",
103 @@ -478,7 +494,7 @@ EXPORT_SYMBOL(ip_conntrack_get);
104 EXPORT_SYMBOL(ip_conntrack_helper_register);
105 EXPORT_SYMBOL(ip_conntrack_helper_unregister);
106 EXPORT_SYMBOL(ip_ct_iterate_cleanup);
107 -EXPORT_SYMBOL(ip_ct_refresh);
108 +EXPORT_SYMBOL(ip_ct_refresh_acct);
109 EXPORT_SYMBOL(ip_ct_find_proto);
110 EXPORT_SYMBOL(__ip_ct_find_proto);
111 EXPORT_SYMBOL(ip_ct_find_helper);
112 --- a/net/ipv4/netfilter/ip_conntrack_proto_generic.c
113 +++ b/net/ipv4/netfilter/ip_conntrack_proto_generic.c
114 @@ -41,9 +41,9 @@ static unsigned int generic_print_conntr
115 /* Returns verdict for packet, or -1 for invalid. */
116 static int established(struct ip_conntrack *conntrack,
117 struct iphdr *iph, size_t len,
118 - enum ip_conntrack_info conntrackinfo)
119 + enum ip_conntrack_info ctinfo)
120 {
121 - ip_ct_refresh(conntrack, ip_ct_generic_timeout);
122 + ip_ct_refresh_acct(conntrack, ctinfo,iph,ip_ct_generic_timeout);
123 return NF_ACCEPT;
124 }
125
126 --- a/net/ipv4/netfilter/ip_conntrack_proto_icmp.c
127 +++ b/net/ipv4/netfilter/ip_conntrack_proto_icmp.c
128 @@ -82,7 +82,7 @@ static int icmp_packet(struct ip_conntra
129 ct->timeout.function((unsigned long)ct);
130 } else {
131 atomic_inc(&ct->proto.icmp.count);
132 - ip_ct_refresh(ct, ip_ct_icmp_timeout);
133 + ip_ct_refresh_acct(ct,ctinfo,iph, ip_ct_icmp_timeout);
134 }
135
136 return NF_ACCEPT;
137 --- a/net/ipv4/netfilter/ip_conntrack_core.c
138 +++ b/net/ipv4/netfilter/ip_conntrack_core.c
139 @@ -1196,22 +1196,40 @@ void ip_conntrack_helper_unregister(stru
140
141 MOD_DEC_USE_COUNT;
142 }
143 +static inline void ct_add_counters(struct ip_conntrack *ct,
144 + enum ip_conntrack_info ctinfo,
145 + const struct iphdr *iph)
146 +{
147 +#if defined(CONFIG_IP_NF_CT_ACCT) || \
148 + defined(CONFIG_IP_NF_CT_ACCT_MODULE)
149 + if (iph) {
150 + ct->counters[CTINFO2DIR(ctinfo)].packets++;
151 + ct->counters[CTINFO2DIR(ctinfo)].bytes +=
152 + ntohs(iph->tot_len);
153 + }
154 +#endif
155 +}
156
157 /* Refresh conntrack for this many jiffies. */
158 -void ip_ct_refresh(struct ip_conntrack *ct, unsigned long extra_jiffies)
159 +void ip_ct_refresh_acct(struct ip_conntrack *ct,
160 + enum ip_conntrack_info ctinfo,
161 + const struct iphdr *iph,
162 + unsigned long extra_jiffies)
163 {
164 IP_NF_ASSERT(ct->timeout.data == (unsigned long)ct);
165
166 WRITE_LOCK(&ip_conntrack_lock);
167 /* If not in hash table, timer will not be active yet */
168 - if (!is_confirmed(ct))
169 + if (!is_confirmed(ct)) {
170 ct->timeout.expires = extra_jiffies;
171 - else {
172 + ct_add_counters(ct, ctinfo,iph);
173 + } else {
174 /* Need del_timer for race avoidance (may already be dying). */
175 if (del_timer(&ct->timeout)) {
176 ct->timeout.expires = jiffies + extra_jiffies;
177 add_timer(&ct->timeout);
178 }
179 + ct_add_counters(ct, ctinfo, iph);
180 }
181 WRITE_UNLOCK(&ip_conntrack_lock);
182 }
183 --- a/include/linux/netfilter_ipv4/ip_conntrack.h
184 +++ b/include/linux/netfilter_ipv4/ip_conntrack.h
185 @@ -164,6 +164,12 @@ struct ip_conntrack_expect
186 union ip_conntrack_expect_help help;
187 };
188
189 +struct ip_conntrack_counter
190 +{
191 + u_int64_t packets;
192 + u_int64_t bytes;
193 +};
194 +
195 struct ip_conntrack_helper;
196
197 struct ip_conntrack
198 @@ -181,6 +187,12 @@ struct ip_conntrack
199 /* Timer function; drops refcnt when it goes off. */
200 struct timer_list timeout;
201
202 +#if defined(CONFIG_IP_NF_CT_ACCT) || \
203 + defined(CONFIG_IP_NF_CT_ACCT_MODULE)
204 + /* Accounting Information (same cache line as other written members) */
205 + struct ip_conntrack_counter counters[IP_CT_DIR_MAX];
206 +#endif
207 +
208 /* If we're expecting another related connection, this will be
209 in expected linked list */
210 struct list_head sibling_list;
211 @@ -264,8 +276,10 @@ extern int invert_tuplepr(struct ip_conn
212 const struct ip_conntrack_tuple *orig);
213
214 /* Refresh conntrack for this many jiffies */
215 -extern void ip_ct_refresh(struct ip_conntrack *ct,
216 - unsigned long extra_jiffies);
217 +extern void ip_ct_refresh_acct(struct ip_conntrack *ct,
218 + enum ip_conntrack_info ctinfo,
219 + const struct iphdr *iph,
220 + unsigned long extra_jiffies);
221
222 /* These are for NAT. Icky. */
223 /* Call me when a conntrack is destroyed. */
224 --- /dev/null
225 +++ b/net/ipv4/netfilter/ipt_connbytes.c
226 @@ -0,0 +1,163 @@
227 +/* Kernel module to match connection tracking byte counter.
228 + * GPL (C) 2002 Martin Devera (devik@cdi.cz).
229 + *
230 + * 2004-07-20 Harald Welte <laforge at netfilter.org>
231 + * - reimplemented to use per-connection accounting counters
232 + * - add functionality to match number of packets
233 + * - add functionality to match average packet size
234 + * - add support to match directions seperately
235 + *
236 + * 2004-10-24 Piotr Chytla <pch at fouk.org>
237 + * - Connbytes with per-connection accouting backported to 2.4
238 + *
239 + */
240 +
241 +#include <linux/module.h>
242 +#include <linux/skbuff.h>
243 +#include <linux/types.h>
244 +#include <linux/netfilter_ipv4/ip_conntrack.h>
245 +#include <linux/netfilter_ipv4/ip_tables.h>
246 +#include <linux/netfilter_ipv4/ipt_connbytes.h>
247 +
248 +#include <asm/div64.h>
249 +
250 +static u_int64_t mydiv(u_int64_t arg1,u_int32_t arg2)
251 +{
252 + do_div(arg1,arg2);
253 + return arg1;
254 +}
255 +
256 +static int
257 +match(const struct sk_buff *skb,
258 + const struct net_device *in,
259 + const struct net_device *out,
260 + const void *matchinfo,
261 + int offset,
262 + const void *hdr,
263 + u_int16_t datalen,
264 + int *hotdrop)
265 +{
266 + static u_int64_t what;
267 + const struct ipt_connbytes_info *sinfo = matchinfo;
268 + enum ip_conntrack_info ctinfo;
269 + struct ip_conntrack *ct;
270 +
271 + if (!(ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo)))
272 + return 0; /* no match */
273 + switch (sinfo->what) {
274 + case IPT_CONNBYTES_PKTS:
275 + switch (sinfo->direction) {
276 + case IPT_CONNBYTES_DIR_ORIGINAL:
277 + what = ct->counters[IP_CT_DIR_ORIGINAL].packets;
278 + break;
279 + case IPT_CONNBYTES_DIR_REPLY:
280 + what = ct->counters[IP_CT_DIR_REPLY].packets;
281 + break;
282 + case IPT_CONNBYTES_DIR_BOTH:
283 + what = ct->counters[IP_CT_DIR_ORIGINAL].packets;
284 + what += ct->counters[IP_CT_DIR_REPLY].packets;
285 + break;
286 + }
287 + break;
288 + case IPT_CONNBYTES_BYTES:
289 + switch (sinfo->direction) {
290 + case IPT_CONNBYTES_DIR_ORIGINAL:
291 + what = ct->counters[IP_CT_DIR_ORIGINAL].bytes;
292 + break;
293 + case IPT_CONNBYTES_DIR_REPLY:
294 + what = ct->counters[IP_CT_DIR_REPLY].bytes;
295 + break;
296 + case IPT_CONNBYTES_DIR_BOTH:
297 + what = ct->counters[IP_CT_DIR_ORIGINAL].bytes;
298 + what += ct->counters[IP_CT_DIR_REPLY].bytes;
299 + break;
300 + }
301 + break;
302 + case IPT_CONNBYTES_AVGPKT:
303 + switch (sinfo->direction) {
304 + case IPT_CONNBYTES_DIR_ORIGINAL:
305 + {
306 + u_int32_t pkts32;
307 +
308 + if (ct->counters[IP_CT_DIR_ORIGINAL].packets > 0xfffffffff)
309 + pkts32 = 0xffffffff;
310 + else
311 + pkts32 = ct->counters[IP_CT_DIR_ORIGINAL].packets;
312 + what = mydiv(ct->counters[IP_CT_DIR_ORIGINAL].bytes,pkts32);
313 + }
314 + break;
315 + case IPT_CONNBYTES_DIR_REPLY:
316 + {
317 + u_int32_t pkts32;
318 +
319 + if (ct->counters[IP_CT_DIR_REPLY].packets > 0xffffffff)
320 + pkts32 = 0xffffffff;
321 + else
322 + pkts32 = ct->counters[IP_CT_DIR_REPLY].packets;
323 + what = mydiv(ct->counters[IP_CT_DIR_REPLY].bytes,pkts32);
324 + }
325 + break;
326 + case IPT_CONNBYTES_DIR_BOTH:
327 + {
328 + u_int64_t bytes;
329 + u_int64_t pkts;
330 + u_int32_t pkts32;
331 + bytes = ct->counters[IP_CT_DIR_ORIGINAL].bytes +
332 + ct->counters[IP_CT_DIR_REPLY].bytes;
333 + pkts = ct->counters[IP_CT_DIR_ORIGINAL].packets +
334 + ct->counters[IP_CT_DIR_REPLY].packets;
335 + if (pkts > 0xffffffff)
336 + pkts32 = 0xffffffff;
337 + else
338 + pkts32 = pkts;
339 + what = mydiv(bytes,pkts);
340 + }
341 + break;
342 + }
343 + break;
344 + }
345 + if (sinfo->count.to)
346 + return (what <= sinfo->count.to && what >= sinfo->count.from);
347 + else
348 + return (what >= sinfo->count.from);
349 +}
350 +
351 +static int check(const char *tablename,
352 + const struct ipt_ip *ip,
353 + void *matchinfo,
354 + unsigned int matchsize,
355 + unsigned int hook_mask)
356 +{
357 + const struct ipt_connbytes_info *sinfo = matchinfo;
358 +
359 + if (matchsize != IPT_ALIGN(sizeof(struct ipt_connbytes_info)))
360 + return 0;
361 + if (sinfo->what != IPT_CONNBYTES_PKTS &&
362 + sinfo->what != IPT_CONNBYTES_BYTES &&
363 + sinfo->what != IPT_CONNBYTES_AVGPKT)
364 + return 0;
365 +
366 + if (sinfo->direction != IPT_CONNBYTES_DIR_ORIGINAL &&
367 + sinfo->direction != IPT_CONNBYTES_DIR_REPLY &&
368 + sinfo->direction != IPT_CONNBYTES_DIR_BOTH)
369 + return 0;
370 +
371 + return 1;
372 +}
373 +
374 +static struct ipt_match state_match
375 += { { NULL, NULL }, "connbytes", &match, &check, NULL, THIS_MODULE };
376 +
377 +static int __init init(void)
378 +{
379 + return ipt_register_match(&state_match);
380 +}
381 +
382 +static void __exit fini(void)
383 +{
384 + ipt_unregister_match(&state_match);
385 +}
386 +
387 +module_init(init);
388 +module_exit(fini);
389 +MODULE_LICENSE("GPL");
390 --- /dev/null
391 +++ b/include/linux/netfilter_ipv4/ipt_connbytes.h
392 @@ -0,0 +1,25 @@
393 +#ifndef _IPT_CONNBYTES_H
394 +#define _IPT_CONNBYTES_H
395 +enum ipt_connbytes_what {
396 + IPT_CONNBYTES_PKTS,
397 + IPT_CONNBYTES_BYTES,
398 + IPT_CONNBYTES_AVGPKT,
399 +};
400 +
401 +enum ipt_connbytes_direction {
402 + IPT_CONNBYTES_DIR_ORIGINAL,
403 + IPT_CONNBYTES_DIR_REPLY,
404 + IPT_CONNBYTES_DIR_BOTH,
405 +};
406 +
407 +struct ipt_connbytes_info
408 +{
409 + struct {
410 + u_int64_t from; /* count to be matched */
411 + u_int64_t to; /* count to be matched */
412 + } count;
413 + u_int8_t what; /* ipt_connbytes_what */
414 + u_int8_t direction; /* ipt_connbytes_direction */
415 +};
416 +
417 +#endif
418 --- a/net/ipv4/netfilter/ip_conntrack_proto_gre.c
419 +++ b/net/ipv4/netfilter/ip_conntrack_proto_gre.c
420 @@ -237,16 +237,16 @@ static unsigned int gre_print_conntrack(
421 /* Returns verdict for packet, and may modify conntrack */
422 static int gre_packet(struct ip_conntrack *ct,
423 struct iphdr *iph, size_t len,
424 - enum ip_conntrack_info conntrackinfo)
425 + enum ip_conntrack_info ctinfo)
426 {
427 /* If we've seen traffic both ways, this is a GRE connection.
428 * Extend timeout. */
429 if (ct->status & IPS_SEEN_REPLY) {
430 - ip_ct_refresh_acct(ct, ct->proto.gre.stream_timeout);
431 + ip_ct_refresh_acct(ct, ctinfo, iph, ct->proto.gre.stream_timeout);
432 /* Also, more likely to be important, and not a probe. */
433 set_bit(IPS_ASSURED_BIT, &ct->status);
434 } else
435 - ip_ct_refresh_acct(ct, ct->proto.gre.timeout);
436 + ip_ct_refresh_acct(ct, ctinfo, iph, ct->proto.gre.timeout);
437
438 return NF_ACCEPT;
439 }