[IPv6] RAW: Compact the API for the kernel
[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/netfilter/x_tables.h>
8 #include <linux/netfilter/xt_connbytes.h>
9 #include <net/netfilter/nf_conntrack.h>
10
11 #include <asm/div64.h>
12
13 MODULE_LICENSE("GPL");
14 MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
15 MODULE_DESCRIPTION("iptables match for matching number of pkts/bytes per connection");
16 MODULE_ALIAS("ipt_connbytes");
17 MODULE_ALIAS("ip6t_connbytes");
18
19 static bool
20 match(const struct sk_buff *skb,
21       const struct net_device *in,
22       const struct net_device *out,
23       const struct xt_match *match,
24       const void *matchinfo,
25       int offset,
26       unsigned int protoff,
27       bool *hotdrop)
28 {
29         const struct xt_connbytes_info *sinfo = matchinfo;
30         const struct nf_conn *ct;
31         enum ip_conntrack_info ctinfo;
32         u_int64_t what = 0;     /* initialize to make gcc happy */
33         u_int64_t bytes = 0;
34         u_int64_t pkts = 0;
35         const struct ip_conntrack_counter *counters;
36
37         ct = nf_ct_get(skb, &ctinfo);
38         if (!ct)
39                 return false;
40         counters = ct->counters;
41
42         switch (sinfo->what) {
43         case XT_CONNBYTES_PKTS:
44                 switch (sinfo->direction) {
45                 case XT_CONNBYTES_DIR_ORIGINAL:
46                         what = counters[IP_CT_DIR_ORIGINAL].packets;
47                         break;
48                 case XT_CONNBYTES_DIR_REPLY:
49                         what = counters[IP_CT_DIR_REPLY].packets;
50                         break;
51                 case XT_CONNBYTES_DIR_BOTH:
52                         what = counters[IP_CT_DIR_ORIGINAL].packets;
53                         what += counters[IP_CT_DIR_REPLY].packets;
54                         break;
55                 }
56                 break;
57         case XT_CONNBYTES_BYTES:
58                 switch (sinfo->direction) {
59                 case XT_CONNBYTES_DIR_ORIGINAL:
60                         what = counters[IP_CT_DIR_ORIGINAL].bytes;
61                         break;
62                 case XT_CONNBYTES_DIR_REPLY:
63                         what = counters[IP_CT_DIR_REPLY].bytes;
64                         break;
65                 case XT_CONNBYTES_DIR_BOTH:
66                         what = counters[IP_CT_DIR_ORIGINAL].bytes;
67                         what += counters[IP_CT_DIR_REPLY].bytes;
68                         break;
69                 }
70                 break;
71         case XT_CONNBYTES_AVGPKT:
72                 switch (sinfo->direction) {
73                 case XT_CONNBYTES_DIR_ORIGINAL:
74                         bytes = counters[IP_CT_DIR_ORIGINAL].bytes;
75                         pkts  = counters[IP_CT_DIR_ORIGINAL].packets;
76                         break;
77                 case XT_CONNBYTES_DIR_REPLY:
78                         bytes = counters[IP_CT_DIR_REPLY].bytes;
79                         pkts  = counters[IP_CT_DIR_REPLY].packets;
80                         break;
81                 case XT_CONNBYTES_DIR_BOTH:
82                         bytes = counters[IP_CT_DIR_ORIGINAL].bytes +
83                                 counters[IP_CT_DIR_REPLY].bytes;
84                         pkts  = counters[IP_CT_DIR_ORIGINAL].packets +
85                                 counters[IP_CT_DIR_REPLY].packets;
86                         break;
87                 }
88                 if (pkts != 0)
89                         what = div64_64(bytes, pkts);
90                 break;
91         }
92
93         if (sinfo->count.to)
94                 return what <= sinfo->count.to && what >= sinfo->count.from;
95         else
96                 return what >= sinfo->count.from;
97 }
98
99 static bool check(const char *tablename,
100                   const void *ip,
101                   const struct xt_match *match,
102                   void *matchinfo,
103                   unsigned int hook_mask)
104 {
105         const struct xt_connbytes_info *sinfo = matchinfo;
106
107         if (sinfo->what != XT_CONNBYTES_PKTS &&
108             sinfo->what != XT_CONNBYTES_BYTES &&
109             sinfo->what != XT_CONNBYTES_AVGPKT)
110                 return false;
111
112         if (sinfo->direction != XT_CONNBYTES_DIR_ORIGINAL &&
113             sinfo->direction != XT_CONNBYTES_DIR_REPLY &&
114             sinfo->direction != XT_CONNBYTES_DIR_BOTH)
115                 return false;
116
117         if (nf_ct_l3proto_try_module_get(match->family) < 0) {
118                 printk(KERN_WARNING "can't load conntrack support for "
119                                     "proto=%d\n", match->family);
120                 return false;
121         }
122
123         return true;
124 }
125
126 static void
127 destroy(const struct xt_match *match, void *matchinfo)
128 {
129         nf_ct_l3proto_module_put(match->family);
130 }
131
132 static struct xt_match xt_connbytes_match[] __read_mostly = {
133         {
134                 .name           = "connbytes",
135                 .family         = AF_INET,
136                 .checkentry     = check,
137                 .match          = match,
138                 .destroy        = destroy,
139                 .matchsize      = sizeof(struct xt_connbytes_info),
140                 .me             = THIS_MODULE
141         },
142         {
143                 .name           = "connbytes",
144                 .family         = AF_INET6,
145                 .checkentry     = check,
146                 .match          = match,
147                 .destroy        = destroy,
148                 .matchsize      = sizeof(struct xt_connbytes_info),
149                 .me             = THIS_MODULE
150         },
151 };
152
153 static int __init xt_connbytes_init(void)
154 {
155         return xt_register_matches(xt_connbytes_match,
156                                    ARRAY_SIZE(xt_connbytes_match));
157 }
158
159 static void __exit xt_connbytes_fini(void)
160 {
161         xt_unregister_matches(xt_connbytes_match,
162                               ARRAY_SIZE(xt_connbytes_match));
163 }
164
165 module_init(xt_connbytes_init);
166 module_exit(xt_connbytes_fini);