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