blob: dd4d79b8fc9d20ced45ef0cfc8204569fe9492da [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).
Harald Welte9d810fd2005-08-13 13:56:26 -07003 */
4#include <linux/module.h>
5#include <linux/skbuff.h>
Harald Welte2e4e6a12006-01-12 13:30:04 -08006#include <linux/netfilter/x_tables.h>
7#include <linux/netfilter/xt_connbytes.h>
Patrick McHardy587aa642007-03-14 16:37:25 -07008#include <net/netfilter/nf_conntrack.h>
Harald Welte9d810fd2005-08-13 13:56:26 -07009
10#include <asm/div64.h>
11#include <asm/bitops.h>
12
13MODULE_LICENSE("GPL");
14MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
15MODULE_DESCRIPTION("iptables match for matching number of pkts/bytes per connection");
Harald Welte2e4e6a12006-01-12 13:30:04 -080016MODULE_ALIAS("ipt_connbytes");
Harald Welte9d810fd2005-08-13 13:56:26 -070017
Jan Engelhardt1d93a9c2007-07-07 22:15:35 -070018static bool
Harald Welte9d810fd2005-08-13 13:56:26 -070019match(const struct sk_buff *skb,
20 const struct net_device *in,
21 const struct net_device *out,
Patrick McHardyc4986732006-03-20 18:02:56 -080022 const struct xt_match *match,
Harald Welte9d810fd2005-08-13 13:56:26 -070023 const void *matchinfo,
24 int offset,
Harald Welte2e4e6a12006-01-12 13:30:04 -080025 unsigned int protoff,
Jan Engelhardtcff533a2007-07-07 22:15:12 -070026 bool *hotdrop)
Harald Welte9d810fd2005-08-13 13:56:26 -070027{
Harald Welte2e4e6a12006-01-12 13:30:04 -080028 const struct xt_connbytes_info *sinfo = matchinfo;
Jan Engelhardta47362a2007-07-07 22:16:55 -070029 const struct nf_conn *ct;
Patrick McHardy587aa642007-03-14 16:37:25 -070030 enum ip_conntrack_info ctinfo;
Harald Welte9d810fd2005-08-13 13:56:26 -070031 u_int64_t what = 0; /* initialize to make gcc happy */
Patrick McHardyfb74a8412007-01-30 14:24:29 -080032 u_int64_t bytes = 0;
33 u_int64_t pkts = 0;
Yasuyuki Kozakai9fb9cbb2005-11-09 16:38:16 -080034 const struct ip_conntrack_counter *counters;
Harald Welte9d810fd2005-08-13 13:56:26 -070035
Patrick McHardy587aa642007-03-14 16:37:25 -070036 ct = nf_ct_get(skb, &ctinfo);
37 if (!ct)
Jan Engelhardt1d93a9c2007-07-07 22:15:35 -070038 return false;
Patrick McHardy587aa642007-03-14 16:37:25 -070039 counters = ct->counters;
Harald Welte9d810fd2005-08-13 13:56:26 -070040
41 switch (sinfo->what) {
Harald Welte2e4e6a12006-01-12 13:30:04 -080042 case XT_CONNBYTES_PKTS:
Harald Welte9d810fd2005-08-13 13:56:26 -070043 switch (sinfo->direction) {
Harald Welte2e4e6a12006-01-12 13:30:04 -080044 case XT_CONNBYTES_DIR_ORIGINAL:
Yasuyuki Kozakai9fb9cbb2005-11-09 16:38:16 -080045 what = counters[IP_CT_DIR_ORIGINAL].packets;
Harald Welte9d810fd2005-08-13 13:56:26 -070046 break;
Harald Welte2e4e6a12006-01-12 13:30:04 -080047 case XT_CONNBYTES_DIR_REPLY:
Yasuyuki Kozakai9fb9cbb2005-11-09 16:38:16 -080048 what = counters[IP_CT_DIR_REPLY].packets;
Harald Welte9d810fd2005-08-13 13:56:26 -070049 break;
Harald Welte2e4e6a12006-01-12 13:30:04 -080050 case XT_CONNBYTES_DIR_BOTH:
Yasuyuki Kozakai9fb9cbb2005-11-09 16:38:16 -080051 what = counters[IP_CT_DIR_ORIGINAL].packets;
52 what += counters[IP_CT_DIR_REPLY].packets;
Harald Welte9d810fd2005-08-13 13:56:26 -070053 break;
54 }
55 break;
Harald Welte2e4e6a12006-01-12 13:30:04 -080056 case XT_CONNBYTES_BYTES:
Harald Welte9d810fd2005-08-13 13:56:26 -070057 switch (sinfo->direction) {
Harald Welte2e4e6a12006-01-12 13:30:04 -080058 case XT_CONNBYTES_DIR_ORIGINAL:
Yasuyuki Kozakai9fb9cbb2005-11-09 16:38:16 -080059 what = counters[IP_CT_DIR_ORIGINAL].bytes;
Harald Welte9d810fd2005-08-13 13:56:26 -070060 break;
Harald Welte2e4e6a12006-01-12 13:30:04 -080061 case XT_CONNBYTES_DIR_REPLY:
Yasuyuki Kozakai9fb9cbb2005-11-09 16:38:16 -080062 what = counters[IP_CT_DIR_REPLY].bytes;
Harald Welte9d810fd2005-08-13 13:56:26 -070063 break;
Harald Welte2e4e6a12006-01-12 13:30:04 -080064 case XT_CONNBYTES_DIR_BOTH:
Yasuyuki Kozakai9fb9cbb2005-11-09 16:38:16 -080065 what = counters[IP_CT_DIR_ORIGINAL].bytes;
66 what += counters[IP_CT_DIR_REPLY].bytes;
Harald Welte9d810fd2005-08-13 13:56:26 -070067 break;
68 }
69 break;
Harald Welte2e4e6a12006-01-12 13:30:04 -080070 case XT_CONNBYTES_AVGPKT:
Harald Welte9d810fd2005-08-13 13:56:26 -070071 switch (sinfo->direction) {
Harald Welte2e4e6a12006-01-12 13:30:04 -080072 case XT_CONNBYTES_DIR_ORIGINAL:
Patrick McHardyfb74a8412007-01-30 14:24:29 -080073 bytes = counters[IP_CT_DIR_ORIGINAL].bytes;
74 pkts = counters[IP_CT_DIR_ORIGINAL].packets;
Harald Welte9d810fd2005-08-13 13:56:26 -070075 break;
Harald Welte2e4e6a12006-01-12 13:30:04 -080076 case XT_CONNBYTES_DIR_REPLY:
Patrick McHardyfb74a8412007-01-30 14:24:29 -080077 bytes = counters[IP_CT_DIR_REPLY].bytes;
78 pkts = counters[IP_CT_DIR_REPLY].packets;
Harald Welte9d810fd2005-08-13 13:56:26 -070079 break;
Harald Welte2e4e6a12006-01-12 13:30:04 -080080 case XT_CONNBYTES_DIR_BOTH:
Patrick McHardyfb74a8412007-01-30 14:24:29 -080081 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;
Harald Welte9d810fd2005-08-13 13:56:26 -070085 break;
86 }
Patrick McHardyfb74a8412007-01-30 14:24:29 -080087 if (pkts != 0)
88 what = div64_64(bytes, pkts);
Harald Welte9d810fd2005-08-13 13:56:26 -070089 break;
90 }
91
92 if (sinfo->count.to)
Jan Engelhardt7c4e36b2007-07-07 22:19:08 -070093 return what <= sinfo->count.to && what >= sinfo->count.from;
Harald Welte9d810fd2005-08-13 13:56:26 -070094 else
Jan Engelhardt7c4e36b2007-07-07 22:19:08 -070095 return what >= sinfo->count.from;
Harald Welte9d810fd2005-08-13 13:56:26 -070096}
97
Jan Engelhardtccb79bd2007-07-07 22:16:00 -070098static bool check(const char *tablename,
99 const void *ip,
100 const struct xt_match *match,
101 void *matchinfo,
102 unsigned int hook_mask)
Harald Welte9d810fd2005-08-13 13:56:26 -0700103{
Harald Welte2e4e6a12006-01-12 13:30:04 -0800104 const struct xt_connbytes_info *sinfo = matchinfo;
Harald Welte9d810fd2005-08-13 13:56:26 -0700105
Harald Welte2e4e6a12006-01-12 13:30:04 -0800106 if (sinfo->what != XT_CONNBYTES_PKTS &&
107 sinfo->what != XT_CONNBYTES_BYTES &&
108 sinfo->what != XT_CONNBYTES_AVGPKT)
Jan Engelhardtccb79bd2007-07-07 22:16:00 -0700109 return false;
Harald Welte9d810fd2005-08-13 13:56:26 -0700110
Harald Welte2e4e6a12006-01-12 13:30:04 -0800111 if (sinfo->direction != XT_CONNBYTES_DIR_ORIGINAL &&
112 sinfo->direction != XT_CONNBYTES_DIR_REPLY &&
113 sinfo->direction != XT_CONNBYTES_DIR_BOTH)
Jan Engelhardtccb79bd2007-07-07 22:16:00 -0700114 return false;
Harald Welte9d810fd2005-08-13 13:56:26 -0700115
Yasuyuki Kozakai11078c32006-12-12 00:29:02 -0800116 if (nf_ct_l3proto_try_module_get(match->family) < 0) {
117 printk(KERN_WARNING "can't load conntrack support for "
118 "proto=%d\n", match->family);
Jan Engelhardtccb79bd2007-07-07 22:16:00 -0700119 return false;
Yasuyuki Kozakai11078c32006-12-12 00:29:02 -0800120 }
121
Jan Engelhardtccb79bd2007-07-07 22:16:00 -0700122 return true;
Harald Welte9d810fd2005-08-13 13:56:26 -0700123}
124
Yasuyuki Kozakai11078c32006-12-12 00:29:02 -0800125static void
126destroy(const struct xt_match *match, void *matchinfo)
127{
128 nf_ct_l3proto_module_put(match->family);
129}
130
Patrick McHardy9f15c532007-07-07 22:22:02 -0700131static struct xt_match xt_connbytes_match[] __read_mostly = {
Patrick McHardy4470bbc2006-08-22 00:34:04 -0700132 {
133 .name = "connbytes",
134 .family = AF_INET,
135 .checkentry = check,
136 .match = match,
Yasuyuki Kozakai11078c32006-12-12 00:29:02 -0800137 .destroy = destroy,
Patrick McHardy4470bbc2006-08-22 00:34:04 -0700138 .matchsize = sizeof(struct xt_connbytes_info),
139 .me = THIS_MODULE
140 },
141 {
142 .name = "connbytes",
143 .family = AF_INET6,
144 .checkentry = check,
145 .match = match,
Yasuyuki Kozakai11078c32006-12-12 00:29:02 -0800146 .destroy = destroy,
Patrick McHardy4470bbc2006-08-22 00:34:04 -0700147 .matchsize = sizeof(struct xt_connbytes_info),
148 .me = THIS_MODULE
149 },
Harald Welte9d810fd2005-08-13 13:56:26 -0700150};
151
Andrew Morton65b4b4e2006-03-28 16:37:06 -0800152static int __init xt_connbytes_init(void)
Harald Welte9d810fd2005-08-13 13:56:26 -0700153{
Patrick McHardy4470bbc2006-08-22 00:34:04 -0700154 return xt_register_matches(xt_connbytes_match,
155 ARRAY_SIZE(xt_connbytes_match));
Harald Welte9d810fd2005-08-13 13:56:26 -0700156}
157
Andrew Morton65b4b4e2006-03-28 16:37:06 -0800158static void __exit xt_connbytes_fini(void)
Harald Welte9d810fd2005-08-13 13:56:26 -0700159{
Patrick McHardy4470bbc2006-08-22 00:34:04 -0700160 xt_unregister_matches(xt_connbytes_match,
161 ARRAY_SIZE(xt_connbytes_match));
Harald Welte9d810fd2005-08-13 13:56:26 -0700162}
163
Andrew Morton65b4b4e2006-03-28 16:37:06 -0800164module_init(xt_connbytes_init);
165module_exit(xt_connbytes_fini);