Merge branches 'irq/sparseirq', 'irq/genirq' and 'irq/urgent'; commit 'v2.6.28' into...
[linux-2.6] / net / netfilter / xt_connbytes.c
1 /* Kernel module to match connection tracking byte counter.
2  * GPL (C) 2002 Martin Devera (devik@cdi.cz).
3  */
4 #include <linux/module.h>
5 #include <linux/bitops.h>
6 #include <linux/skbuff.h>
7 #include <linux/math64.h>
8 #include <linux/netfilter/x_tables.h>
9 #include <linux/netfilter/xt_connbytes.h>
10 #include <net/netfilter/nf_conntrack.h>
11 #include <net/netfilter/nf_conntrack_acct.h>
12
13 MODULE_LICENSE("GPL");
14 MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
15 MODULE_DESCRIPTION("Xtables: Number of packets/bytes per connection matching");
16 MODULE_ALIAS("ipt_connbytes");
17 MODULE_ALIAS("ip6t_connbytes");
18
19 static bool
20 connbytes_mt(const struct sk_buff *skb, const struct xt_match_param *par)
21 {
22         const struct xt_connbytes_info *sinfo = par->matchinfo;
23         const struct nf_conn *ct;
24         enum ip_conntrack_info ctinfo;
25         u_int64_t what = 0;     /* initialize to make gcc happy */
26         u_int64_t bytes = 0;
27         u_int64_t pkts = 0;
28         const struct nf_conn_counter *counters;
29
30         ct = nf_ct_get(skb, &ctinfo);
31         if (!ct)
32                 return false;
33
34         counters = nf_conn_acct_find(ct);
35         if (!counters)
36                 return false;
37
38         switch (sinfo->what) {
39         case XT_CONNBYTES_PKTS:
40                 switch (sinfo->direction) {
41                 case XT_CONNBYTES_DIR_ORIGINAL:
42                         what = counters[IP_CT_DIR_ORIGINAL].packets;
43                         break;
44                 case XT_CONNBYTES_DIR_REPLY:
45                         what = counters[IP_CT_DIR_REPLY].packets;
46                         break;
47                 case XT_CONNBYTES_DIR_BOTH:
48                         what = counters[IP_CT_DIR_ORIGINAL].packets;
49                         what += counters[IP_CT_DIR_REPLY].packets;
50                         break;
51                 }
52                 break;
53         case XT_CONNBYTES_BYTES:
54                 switch (sinfo->direction) {
55                 case XT_CONNBYTES_DIR_ORIGINAL:
56                         what = counters[IP_CT_DIR_ORIGINAL].bytes;
57                         break;
58                 case XT_CONNBYTES_DIR_REPLY:
59                         what = counters[IP_CT_DIR_REPLY].bytes;
60                         break;
61                 case XT_CONNBYTES_DIR_BOTH:
62                         what = counters[IP_CT_DIR_ORIGINAL].bytes;
63                         what += counters[IP_CT_DIR_REPLY].bytes;
64                         break;
65                 }
66                 break;
67         case XT_CONNBYTES_AVGPKT:
68                 switch (sinfo->direction) {
69                 case XT_CONNBYTES_DIR_ORIGINAL:
70                         bytes = counters[IP_CT_DIR_ORIGINAL].bytes;
71                         pkts  = counters[IP_CT_DIR_ORIGINAL].packets;
72                         break;
73                 case XT_CONNBYTES_DIR_REPLY:
74                         bytes = counters[IP_CT_DIR_REPLY].bytes;
75                         pkts  = counters[IP_CT_DIR_REPLY].packets;
76                         break;
77                 case XT_CONNBYTES_DIR_BOTH:
78                         bytes = counters[IP_CT_DIR_ORIGINAL].bytes +
79                                 counters[IP_CT_DIR_REPLY].bytes;
80                         pkts  = counters[IP_CT_DIR_ORIGINAL].packets +
81                                 counters[IP_CT_DIR_REPLY].packets;
82                         break;
83                 }
84                 if (pkts != 0)
85                         what = div64_u64(bytes, pkts);
86                 break;
87         }
88
89         if (sinfo->count.to)
90                 return what <= sinfo->count.to && what >= sinfo->count.from;
91         else
92                 return what >= sinfo->count.from;
93 }
94
95 static bool connbytes_mt_check(const struct xt_mtchk_param *par)
96 {
97         const struct xt_connbytes_info *sinfo = par->matchinfo;
98
99         if (sinfo->what != XT_CONNBYTES_PKTS &&
100             sinfo->what != XT_CONNBYTES_BYTES &&
101             sinfo->what != XT_CONNBYTES_AVGPKT)
102                 return false;
103
104         if (sinfo->direction != XT_CONNBYTES_DIR_ORIGINAL &&
105             sinfo->direction != XT_CONNBYTES_DIR_REPLY &&
106             sinfo->direction != XT_CONNBYTES_DIR_BOTH)
107                 return false;
108
109         if (nf_ct_l3proto_try_module_get(par->family) < 0) {
110                 printk(KERN_WARNING "can't load conntrack support for "
111                                     "proto=%u\n", par->family);
112                 return false;
113         }
114
115         return true;
116 }
117
118 static void connbytes_mt_destroy(const struct xt_mtdtor_param *par)
119 {
120         nf_ct_l3proto_module_put(par->family);
121 }
122
123 static struct xt_match connbytes_mt_reg __read_mostly = {
124         .name       = "connbytes",
125         .revision   = 0,
126         .family     = NFPROTO_UNSPEC,
127         .checkentry = connbytes_mt_check,
128         .match      = connbytes_mt,
129         .destroy    = connbytes_mt_destroy,
130         .matchsize  = sizeof(struct xt_connbytes_info),
131         .me         = THIS_MODULE,
132 };
133
134 static int __init connbytes_mt_init(void)
135 {
136         return xt_register_match(&connbytes_mt_reg);
137 }
138
139 static void __exit connbytes_mt_exit(void)
140 {
141         xt_unregister_match(&connbytes_mt_reg);
142 }
143
144 module_init(connbytes_mt_init);
145 module_exit(connbytes_mt_exit);