netfilter: Introduce NFPROTO_* constants
[linux-block.git] / net / netfilter / xt_connbytes.c
CommitLineData
9d810fd2
HW
1/* Kernel module to match connection tracking byte counter.
2 * GPL (C) 2002 Martin Devera (devik@cdi.cz).
9d810fd2
HW
3 */
4#include <linux/module.h>
1977f032 5#include <linux/bitops.h>
9d810fd2 6#include <linux/skbuff.h>
6f6d6a1a 7#include <linux/math64.h>
2e4e6a17
HW
8#include <linux/netfilter/x_tables.h>
9#include <linux/netfilter/xt_connbytes.h>
587aa641 10#include <net/netfilter/nf_conntrack.h>
58401572 11#include <net/netfilter/nf_conntrack_acct.h>
9d810fd2 12
9d810fd2
HW
13MODULE_LICENSE("GPL");
14MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
2ae15b64 15MODULE_DESCRIPTION("Xtables: Number of packets/bytes per connection matching");
2e4e6a17 16MODULE_ALIAS("ipt_connbytes");
73aaf935 17MODULE_ALIAS("ip6t_connbytes");
9d810fd2 18
1d93a9cb 19static bool
d3c5ee6d
JE
20connbytes_mt(const struct sk_buff *skb, const struct net_device *in,
21 const struct net_device *out, const struct xt_match *match,
22 const void *matchinfo, int offset, unsigned int protoff,
23 bool *hotdrop)
9d810fd2 24{
2e4e6a17 25 const struct xt_connbytes_info *sinfo = matchinfo;
a47362a2 26 const struct nf_conn *ct;
587aa641 27 enum ip_conntrack_info ctinfo;
9d810fd2 28 u_int64_t what = 0; /* initialize to make gcc happy */
fb74a841
PM
29 u_int64_t bytes = 0;
30 u_int64_t pkts = 0;
58401572 31 const struct nf_conn_counter *counters;
9d810fd2 32
587aa641
PM
33 ct = nf_ct_get(skb, &ctinfo);
34 if (!ct)
1d93a9cb 35 return false;
58401572
KPO
36
37 counters = nf_conn_acct_find(ct);
38 if (!counters)
39 return false;
9d810fd2
HW
40
41 switch (sinfo->what) {
2e4e6a17 42 case XT_CONNBYTES_PKTS:
9d810fd2 43 switch (sinfo->direction) {
2e4e6a17 44 case XT_CONNBYTES_DIR_ORIGINAL:
9fb9cbb1 45 what = counters[IP_CT_DIR_ORIGINAL].packets;
9d810fd2 46 break;
2e4e6a17 47 case XT_CONNBYTES_DIR_REPLY:
9fb9cbb1 48 what = counters[IP_CT_DIR_REPLY].packets;
9d810fd2 49 break;
2e4e6a17 50 case XT_CONNBYTES_DIR_BOTH:
9fb9cbb1
YK
51 what = counters[IP_CT_DIR_ORIGINAL].packets;
52 what += counters[IP_CT_DIR_REPLY].packets;
9d810fd2
HW
53 break;
54 }
55 break;
2e4e6a17 56 case XT_CONNBYTES_BYTES:
9d810fd2 57 switch (sinfo->direction) {
2e4e6a17 58 case XT_CONNBYTES_DIR_ORIGINAL:
9fb9cbb1 59 what = counters[IP_CT_DIR_ORIGINAL].bytes;
9d810fd2 60 break;
2e4e6a17 61 case XT_CONNBYTES_DIR_REPLY:
9fb9cbb1 62 what = counters[IP_CT_DIR_REPLY].bytes;
9d810fd2 63 break;
2e4e6a17 64 case XT_CONNBYTES_DIR_BOTH:
9fb9cbb1
YK
65 what = counters[IP_CT_DIR_ORIGINAL].bytes;
66 what += counters[IP_CT_DIR_REPLY].bytes;
9d810fd2
HW
67 break;
68 }
69 break;
2e4e6a17 70 case XT_CONNBYTES_AVGPKT:
9d810fd2 71 switch (sinfo->direction) {
2e4e6a17 72 case XT_CONNBYTES_DIR_ORIGINAL:
fb74a841
PM
73 bytes = counters[IP_CT_DIR_ORIGINAL].bytes;
74 pkts = counters[IP_CT_DIR_ORIGINAL].packets;
9d810fd2 75 break;
2e4e6a17 76 case XT_CONNBYTES_DIR_REPLY:
fb74a841
PM
77 bytes = counters[IP_CT_DIR_REPLY].bytes;
78 pkts = counters[IP_CT_DIR_REPLY].packets;
9d810fd2 79 break;
2e4e6a17 80 case XT_CONNBYTES_DIR_BOTH:
fb74a841
PM
81 bytes = counters[IP_CT_DIR_ORIGINAL].bytes +
82 counters[IP_CT_DIR_REPLY].bytes;
83 pkts = counters[IP_CT_DIR_ORIGINAL].packets +
84 counters[IP_CT_DIR_REPLY].packets;
9d810fd2
HW
85 break;
86 }
fb74a841 87 if (pkts != 0)
6f6d6a1a 88 what = div64_u64(bytes, pkts);
9d810fd2
HW
89 break;
90 }
91
92 if (sinfo->count.to)
7c4e36bc 93 return what <= sinfo->count.to && what >= sinfo->count.from;
9d810fd2 94 else
7c4e36bc 95 return what >= sinfo->count.from;
9d810fd2
HW
96}
97
d3c5ee6d
JE
98static bool
99connbytes_mt_check(const char *tablename, const void *ip,
100 const struct xt_match *match, void *matchinfo,
101 unsigned int hook_mask)
9d810fd2 102{
2e4e6a17 103 const struct xt_connbytes_info *sinfo = matchinfo;
9d810fd2 104
2e4e6a17
HW
105 if (sinfo->what != XT_CONNBYTES_PKTS &&
106 sinfo->what != XT_CONNBYTES_BYTES &&
107 sinfo->what != XT_CONNBYTES_AVGPKT)
ccb79bdc 108 return false;
9d810fd2 109
2e4e6a17
HW
110 if (sinfo->direction != XT_CONNBYTES_DIR_ORIGINAL &&
111 sinfo->direction != XT_CONNBYTES_DIR_REPLY &&
112 sinfo->direction != XT_CONNBYTES_DIR_BOTH)
ccb79bdc 113 return false;
9d810fd2 114
11078c37
YK
115 if (nf_ct_l3proto_try_module_get(match->family) < 0) {
116 printk(KERN_WARNING "can't load conntrack support for "
df54aae0 117 "proto=%u\n", match->family);
ccb79bdc 118 return false;
11078c37
YK
119 }
120
ccb79bdc 121 return true;
9d810fd2
HW
122}
123
11078c37 124static void
d3c5ee6d 125connbytes_mt_destroy(const struct xt_match *match, void *matchinfo)
11078c37
YK
126{
127 nf_ct_l3proto_module_put(match->family);
128}
129
d3c5ee6d 130static struct xt_match connbytes_mt_reg[] __read_mostly = {
4470bbc7
PM
131 {
132 .name = "connbytes",
133 .family = AF_INET,
d3c5ee6d
JE
134 .checkentry = connbytes_mt_check,
135 .match = connbytes_mt,
136 .destroy = connbytes_mt_destroy,
4470bbc7
PM
137 .matchsize = sizeof(struct xt_connbytes_info),
138 .me = THIS_MODULE
139 },
140 {
141 .name = "connbytes",
142 .family = AF_INET6,
d3c5ee6d
JE
143 .checkentry = connbytes_mt_check,
144 .match = connbytes_mt,
145 .destroy = connbytes_mt_destroy,
4470bbc7
PM
146 .matchsize = sizeof(struct xt_connbytes_info),
147 .me = THIS_MODULE
148 },
9d810fd2
HW
149};
150
d3c5ee6d 151static int __init connbytes_mt_init(void)
9d810fd2 152{
d3c5ee6d
JE
153 return xt_register_matches(connbytes_mt_reg,
154 ARRAY_SIZE(connbytes_mt_reg));
9d810fd2
HW
155}
156
d3c5ee6d 157static void __exit connbytes_mt_exit(void)
9d810fd2 158{
d3c5ee6d 159 xt_unregister_matches(connbytes_mt_reg, ARRAY_SIZE(connbytes_mt_reg));
9d810fd2
HW
160}
161
d3c5ee6d
JE
162module_init(connbytes_mt_init);
163module_exit(connbytes_mt_exit);