blob: 302043bc41b23f6b2e435f1cad3f2bf17ae2ce44 [file] [log] [blame]
Harald Welte9d810fd2005-08-13 13:56:26 -07001/* Kernel module to match connection tracking byte counter.
2 * GPL (C) 2002 Martin Devera (devik@cdi.cz).
3 *
4 * 2004-07-20 Harald Welte <laforge@netfilter.org>
5 * - reimplemented to use per-connection accounting counters
6 * - add functionality to match number of packets
7 * - add functionality to match average packet size
8 * - add support to match directions seperately
Harald Welte2e4e6a12006-01-12 13:30:04 -08009 * 2005-10-16 Harald Welte <laforge@netfilter.org>
10 * - Port to x_tables
Harald Welte9d810fd2005-08-13 13:56:26 -070011 *
12 */
13#include <linux/module.h>
14#include <linux/skbuff.h>
Yasuyuki Kozakai9fb9cbb2005-11-09 16:38:16 -080015#include <net/netfilter/nf_conntrack_compat.h>
Harald Welte2e4e6a12006-01-12 13:30:04 -080016#include <linux/netfilter/x_tables.h>
17#include <linux/netfilter/xt_connbytes.h>
Harald Welte9d810fd2005-08-13 13:56:26 -070018
19#include <asm/div64.h>
20#include <asm/bitops.h>
21
22MODULE_LICENSE("GPL");
23MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
24MODULE_DESCRIPTION("iptables match for matching number of pkts/bytes per connection");
Harald Welte2e4e6a12006-01-12 13:30:04 -080025MODULE_ALIAS("ipt_connbytes");
Harald Welte9d810fd2005-08-13 13:56:26 -070026
Harald Welte9d810fd2005-08-13 13:56:26 -070027static int
28match(const struct sk_buff *skb,
29 const struct net_device *in,
30 const struct net_device *out,
Patrick McHardyc4986732006-03-20 18:02:56 -080031 const struct xt_match *match,
Harald Welte9d810fd2005-08-13 13:56:26 -070032 const void *matchinfo,
33 int offset,
Harald Welte2e4e6a12006-01-12 13:30:04 -080034 unsigned int protoff,
Harald Welte9d810fd2005-08-13 13:56:26 -070035 int *hotdrop)
36{
Harald Welte2e4e6a12006-01-12 13:30:04 -080037 const struct xt_connbytes_info *sinfo = matchinfo;
Harald Welte9d810fd2005-08-13 13:56:26 -070038 u_int64_t what = 0; /* initialize to make gcc happy */
Patrick McHardyfb74a8412007-01-30 14:24:29 -080039 u_int64_t bytes = 0;
40 u_int64_t pkts = 0;
Yasuyuki Kozakai9fb9cbb2005-11-09 16:38:16 -080041 const struct ip_conntrack_counter *counters;
Harald Welte9d810fd2005-08-13 13:56:26 -070042
Yasuyuki Kozakai9fb9cbb2005-11-09 16:38:16 -080043 if (!(counters = nf_ct_get_counters(skb)))
Harald Welte9d810fd2005-08-13 13:56:26 -070044 return 0; /* no match */
45
46 switch (sinfo->what) {
Harald Welte2e4e6a12006-01-12 13:30:04 -080047 case XT_CONNBYTES_PKTS:
Harald Welte9d810fd2005-08-13 13:56:26 -070048 switch (sinfo->direction) {
Harald Welte2e4e6a12006-01-12 13:30:04 -080049 case XT_CONNBYTES_DIR_ORIGINAL:
Yasuyuki Kozakai9fb9cbb2005-11-09 16:38:16 -080050 what = counters[IP_CT_DIR_ORIGINAL].packets;
Harald Welte9d810fd2005-08-13 13:56:26 -070051 break;
Harald Welte2e4e6a12006-01-12 13:30:04 -080052 case XT_CONNBYTES_DIR_REPLY:
Yasuyuki Kozakai9fb9cbb2005-11-09 16:38:16 -080053 what = counters[IP_CT_DIR_REPLY].packets;
Harald Welte9d810fd2005-08-13 13:56:26 -070054 break;
Harald Welte2e4e6a12006-01-12 13:30:04 -080055 case XT_CONNBYTES_DIR_BOTH:
Yasuyuki Kozakai9fb9cbb2005-11-09 16:38:16 -080056 what = counters[IP_CT_DIR_ORIGINAL].packets;
57 what += counters[IP_CT_DIR_REPLY].packets;
Harald Welte9d810fd2005-08-13 13:56:26 -070058 break;
59 }
60 break;
Harald Welte2e4e6a12006-01-12 13:30:04 -080061 case XT_CONNBYTES_BYTES:
Harald Welte9d810fd2005-08-13 13:56:26 -070062 switch (sinfo->direction) {
Harald Welte2e4e6a12006-01-12 13:30:04 -080063 case XT_CONNBYTES_DIR_ORIGINAL:
Yasuyuki Kozakai9fb9cbb2005-11-09 16:38:16 -080064 what = counters[IP_CT_DIR_ORIGINAL].bytes;
Harald Welte9d810fd2005-08-13 13:56:26 -070065 break;
Harald Welte2e4e6a12006-01-12 13:30:04 -080066 case XT_CONNBYTES_DIR_REPLY:
Yasuyuki Kozakai9fb9cbb2005-11-09 16:38:16 -080067 what = counters[IP_CT_DIR_REPLY].bytes;
Harald Welte9d810fd2005-08-13 13:56:26 -070068 break;
Harald Welte2e4e6a12006-01-12 13:30:04 -080069 case XT_CONNBYTES_DIR_BOTH:
Yasuyuki Kozakai9fb9cbb2005-11-09 16:38:16 -080070 what = counters[IP_CT_DIR_ORIGINAL].bytes;
71 what += counters[IP_CT_DIR_REPLY].bytes;
Harald Welte9d810fd2005-08-13 13:56:26 -070072 break;
73 }
74 break;
Harald Welte2e4e6a12006-01-12 13:30:04 -080075 case XT_CONNBYTES_AVGPKT:
Harald Welte9d810fd2005-08-13 13:56:26 -070076 switch (sinfo->direction) {
Harald Welte2e4e6a12006-01-12 13:30:04 -080077 case XT_CONNBYTES_DIR_ORIGINAL:
Patrick McHardyfb74a8412007-01-30 14:24:29 -080078 bytes = counters[IP_CT_DIR_ORIGINAL].bytes;
79 pkts = counters[IP_CT_DIR_ORIGINAL].packets;
Harald Welte9d810fd2005-08-13 13:56:26 -070080 break;
Harald Welte2e4e6a12006-01-12 13:30:04 -080081 case XT_CONNBYTES_DIR_REPLY:
Patrick McHardyfb74a8412007-01-30 14:24:29 -080082 bytes = counters[IP_CT_DIR_REPLY].bytes;
83 pkts = counters[IP_CT_DIR_REPLY].packets;
Harald Welte9d810fd2005-08-13 13:56:26 -070084 break;
Harald Welte2e4e6a12006-01-12 13:30:04 -080085 case XT_CONNBYTES_DIR_BOTH:
Patrick McHardyfb74a8412007-01-30 14:24:29 -080086 bytes = counters[IP_CT_DIR_ORIGINAL].bytes +
87 counters[IP_CT_DIR_REPLY].bytes;
88 pkts = counters[IP_CT_DIR_ORIGINAL].packets +
89 counters[IP_CT_DIR_REPLY].packets;
Harald Welte9d810fd2005-08-13 13:56:26 -070090 break;
91 }
Patrick McHardyfb74a8412007-01-30 14:24:29 -080092 if (pkts != 0)
93 what = div64_64(bytes, pkts);
Harald Welte9d810fd2005-08-13 13:56:26 -070094 break;
95 }
96
97 if (sinfo->count.to)
98 return (what <= sinfo->count.to && what >= sinfo->count.from);
99 else
100 return (what >= sinfo->count.from);
101}
102
103static int check(const char *tablename,
Harald Welte2e4e6a12006-01-12 13:30:04 -0800104 const void *ip,
Patrick McHardyc4986732006-03-20 18:02:56 -0800105 const struct xt_match *match,
Harald Welte9d810fd2005-08-13 13:56:26 -0700106 void *matchinfo,
Harald Welte9d810fd2005-08-13 13:56:26 -0700107 unsigned int hook_mask)
108{
Harald Welte2e4e6a12006-01-12 13:30:04 -0800109 const struct xt_connbytes_info *sinfo = matchinfo;
Harald Welte9d810fd2005-08-13 13:56:26 -0700110
Harald Welte2e4e6a12006-01-12 13:30:04 -0800111 if (sinfo->what != XT_CONNBYTES_PKTS &&
112 sinfo->what != XT_CONNBYTES_BYTES &&
113 sinfo->what != XT_CONNBYTES_AVGPKT)
Harald Welte9d810fd2005-08-13 13:56:26 -0700114 return 0;
115
Harald Welte2e4e6a12006-01-12 13:30:04 -0800116 if (sinfo->direction != XT_CONNBYTES_DIR_ORIGINAL &&
117 sinfo->direction != XT_CONNBYTES_DIR_REPLY &&
118 sinfo->direction != XT_CONNBYTES_DIR_BOTH)
Harald Welte9d810fd2005-08-13 13:56:26 -0700119 return 0;
120
Yasuyuki Kozakai11078c32006-12-12 00:29:02 -0800121 if (nf_ct_l3proto_try_module_get(match->family) < 0) {
122 printk(KERN_WARNING "can't load conntrack support for "
123 "proto=%d\n", match->family);
124 return 0;
125 }
126
Harald Welte9d810fd2005-08-13 13:56:26 -0700127 return 1;
128}
129
Yasuyuki Kozakai11078c32006-12-12 00:29:02 -0800130static void
131destroy(const struct xt_match *match, void *matchinfo)
132{
133 nf_ct_l3proto_module_put(match->family);
134}
135
Patrick McHardyfe1cb102006-08-22 00:35:47 -0700136static struct xt_match xt_connbytes_match[] = {
Patrick McHardy4470bbc2006-08-22 00:34:04 -0700137 {
138 .name = "connbytes",
139 .family = AF_INET,
140 .checkentry = check,
141 .match = match,
Yasuyuki Kozakai11078c32006-12-12 00:29:02 -0800142 .destroy = destroy,
Patrick McHardy4470bbc2006-08-22 00:34:04 -0700143 .matchsize = sizeof(struct xt_connbytes_info),
144 .me = THIS_MODULE
145 },
146 {
147 .name = "connbytes",
148 .family = AF_INET6,
149 .checkentry = check,
150 .match = match,
Yasuyuki Kozakai11078c32006-12-12 00:29:02 -0800151 .destroy = destroy,
Patrick McHardy4470bbc2006-08-22 00:34:04 -0700152 .matchsize = sizeof(struct xt_connbytes_info),
153 .me = THIS_MODULE
154 },
Harald Welte9d810fd2005-08-13 13:56:26 -0700155};
156
Andrew Morton65b4b4e2006-03-28 16:37:06 -0800157static int __init xt_connbytes_init(void)
Harald Welte9d810fd2005-08-13 13:56:26 -0700158{
Patrick McHardy4470bbc2006-08-22 00:34:04 -0700159 return xt_register_matches(xt_connbytes_match,
160 ARRAY_SIZE(xt_connbytes_match));
Harald Welte9d810fd2005-08-13 13:56:26 -0700161}
162
Andrew Morton65b4b4e2006-03-28 16:37:06 -0800163static void __exit xt_connbytes_fini(void)
Harald Welte9d810fd2005-08-13 13:56:26 -0700164{
Patrick McHardy4470bbc2006-08-22 00:34:04 -0700165 xt_unregister_matches(xt_connbytes_match,
166 ARRAY_SIZE(xt_connbytes_match));
Harald Welte9d810fd2005-08-13 13:56:26 -0700167}
168
Andrew Morton65b4b4e2006-03-28 16:37:06 -0800169module_init(xt_connbytes_init);
170module_exit(xt_connbytes_fini);