blob: d7e8983cd37f6303921edf25bc201eca7e99c4a2 [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>
Jiri Slaby1977f032007-10-18 23:40:25 -07005#include <linux/bitops.h>
Harald Welte9d810fd2005-08-13 13:56:26 -07006#include <linux/skbuff.h>
Roman Zippel6f6d6a12008-05-01 04:34:28 -07007#include <linux/math64.h>
Harald Welte2e4e6a12006-01-12 13:30:04 -08008#include <linux/netfilter/x_tables.h>
9#include <linux/netfilter/xt_connbytes.h>
Patrick McHardy587aa642007-03-14 16:37:25 -070010#include <net/netfilter/nf_conntrack.h>
Harald Welte9d810fd2005-08-13 13:56:26 -070011
Harald Welte9d810fd2005-08-13 13:56:26 -070012MODULE_LICENSE("GPL");
13MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
Jan Engelhardt2ae15b62008-01-14 23:42:28 -080014MODULE_DESCRIPTION("Xtables: Number of packets/bytes per connection matching");
Harald Welte2e4e6a12006-01-12 13:30:04 -080015MODULE_ALIAS("ipt_connbytes");
Jan Engelhardt73aaf932007-10-11 14:36:40 -070016MODULE_ALIAS("ip6t_connbytes");
Harald Welte9d810fd2005-08-13 13:56:26 -070017
Jan Engelhardt1d93a9c2007-07-07 22:15:35 -070018static bool
Jan Engelhardtd3c5ee62007-12-04 23:24:03 -080019connbytes_mt(const struct sk_buff *skb, const struct net_device *in,
20 const struct net_device *out, const struct xt_match *match,
21 const void *matchinfo, int offset, unsigned int protoff,
22 bool *hotdrop)
Harald Welte9d810fd2005-08-13 13:56:26 -070023{
Harald Welte2e4e6a12006-01-12 13:30:04 -080024 const struct xt_connbytes_info *sinfo = matchinfo;
Jan Engelhardta47362a2007-07-07 22:16:55 -070025 const struct nf_conn *ct;
Patrick McHardy587aa642007-03-14 16:37:25 -070026 enum ip_conntrack_info ctinfo;
Harald Welte9d810fd2005-08-13 13:56:26 -070027 u_int64_t what = 0; /* initialize to make gcc happy */
Patrick McHardyfb74a8412007-01-30 14:24:29 -080028 u_int64_t bytes = 0;
29 u_int64_t pkts = 0;
Yasuyuki Kozakai9fb9cbb2005-11-09 16:38:16 -080030 const struct ip_conntrack_counter *counters;
Harald Welte9d810fd2005-08-13 13:56:26 -070031
Patrick McHardy587aa642007-03-14 16:37:25 -070032 ct = nf_ct_get(skb, &ctinfo);
33 if (!ct)
Jan Engelhardt1d93a9c2007-07-07 22:15:35 -070034 return false;
Patrick McHardy587aa642007-03-14 16:37:25 -070035 counters = ct->counters;
Harald Welte9d810fd2005-08-13 13:56:26 -070036
37 switch (sinfo->what) {
Harald Welte2e4e6a12006-01-12 13:30:04 -080038 case XT_CONNBYTES_PKTS:
Harald Welte9d810fd2005-08-13 13:56:26 -070039 switch (sinfo->direction) {
Harald Welte2e4e6a12006-01-12 13:30:04 -080040 case XT_CONNBYTES_DIR_ORIGINAL:
Yasuyuki Kozakai9fb9cbb2005-11-09 16:38:16 -080041 what = counters[IP_CT_DIR_ORIGINAL].packets;
Harald Welte9d810fd2005-08-13 13:56:26 -070042 break;
Harald Welte2e4e6a12006-01-12 13:30:04 -080043 case XT_CONNBYTES_DIR_REPLY:
Yasuyuki Kozakai9fb9cbb2005-11-09 16:38:16 -080044 what = counters[IP_CT_DIR_REPLY].packets;
Harald Welte9d810fd2005-08-13 13:56:26 -070045 break;
Harald Welte2e4e6a12006-01-12 13:30:04 -080046 case XT_CONNBYTES_DIR_BOTH:
Yasuyuki Kozakai9fb9cbb2005-11-09 16:38:16 -080047 what = counters[IP_CT_DIR_ORIGINAL].packets;
48 what += counters[IP_CT_DIR_REPLY].packets;
Harald Welte9d810fd2005-08-13 13:56:26 -070049 break;
50 }
51 break;
Harald Welte2e4e6a12006-01-12 13:30:04 -080052 case XT_CONNBYTES_BYTES:
Harald Welte9d810fd2005-08-13 13:56:26 -070053 switch (sinfo->direction) {
Harald Welte2e4e6a12006-01-12 13:30:04 -080054 case XT_CONNBYTES_DIR_ORIGINAL:
Yasuyuki Kozakai9fb9cbb2005-11-09 16:38:16 -080055 what = counters[IP_CT_DIR_ORIGINAL].bytes;
Harald Welte9d810fd2005-08-13 13:56:26 -070056 break;
Harald Welte2e4e6a12006-01-12 13:30:04 -080057 case XT_CONNBYTES_DIR_REPLY:
Yasuyuki Kozakai9fb9cbb2005-11-09 16:38:16 -080058 what = counters[IP_CT_DIR_REPLY].bytes;
Harald Welte9d810fd2005-08-13 13:56:26 -070059 break;
Harald Welte2e4e6a12006-01-12 13:30:04 -080060 case XT_CONNBYTES_DIR_BOTH:
Yasuyuki Kozakai9fb9cbb2005-11-09 16:38:16 -080061 what = counters[IP_CT_DIR_ORIGINAL].bytes;
62 what += counters[IP_CT_DIR_REPLY].bytes;
Harald Welte9d810fd2005-08-13 13:56:26 -070063 break;
64 }
65 break;
Harald Welte2e4e6a12006-01-12 13:30:04 -080066 case XT_CONNBYTES_AVGPKT:
Harald Welte9d810fd2005-08-13 13:56:26 -070067 switch (sinfo->direction) {
Harald Welte2e4e6a12006-01-12 13:30:04 -080068 case XT_CONNBYTES_DIR_ORIGINAL:
Patrick McHardyfb74a8412007-01-30 14:24:29 -080069 bytes = counters[IP_CT_DIR_ORIGINAL].bytes;
70 pkts = counters[IP_CT_DIR_ORIGINAL].packets;
Harald Welte9d810fd2005-08-13 13:56:26 -070071 break;
Harald Welte2e4e6a12006-01-12 13:30:04 -080072 case XT_CONNBYTES_DIR_REPLY:
Patrick McHardyfb74a8412007-01-30 14:24:29 -080073 bytes = counters[IP_CT_DIR_REPLY].bytes;
74 pkts = counters[IP_CT_DIR_REPLY].packets;
Harald Welte9d810fd2005-08-13 13:56:26 -070075 break;
Harald Welte2e4e6a12006-01-12 13:30:04 -080076 case XT_CONNBYTES_DIR_BOTH:
Patrick McHardyfb74a8412007-01-30 14:24:29 -080077 bytes = counters[IP_CT_DIR_ORIGINAL].bytes +
78 counters[IP_CT_DIR_REPLY].bytes;
79 pkts = counters[IP_CT_DIR_ORIGINAL].packets +
80 counters[IP_CT_DIR_REPLY].packets;
Harald Welte9d810fd2005-08-13 13:56:26 -070081 break;
82 }
Patrick McHardyfb74a8412007-01-30 14:24:29 -080083 if (pkts != 0)
Roman Zippel6f6d6a12008-05-01 04:34:28 -070084 what = div64_u64(bytes, pkts);
Harald Welte9d810fd2005-08-13 13:56:26 -070085 break;
86 }
87
88 if (sinfo->count.to)
Jan Engelhardt7c4e36b2007-07-07 22:19:08 -070089 return what <= sinfo->count.to && what >= sinfo->count.from;
Harald Welte9d810fd2005-08-13 13:56:26 -070090 else
Jan Engelhardt7c4e36b2007-07-07 22:19:08 -070091 return what >= sinfo->count.from;
Harald Welte9d810fd2005-08-13 13:56:26 -070092}
93
Jan Engelhardtd3c5ee62007-12-04 23:24:03 -080094static bool
95connbytes_mt_check(const char *tablename, const void *ip,
96 const struct xt_match *match, void *matchinfo,
97 unsigned int hook_mask)
Harald Welte9d810fd2005-08-13 13:56:26 -070098{
Harald Welte2e4e6a12006-01-12 13:30:04 -080099 const struct xt_connbytes_info *sinfo = matchinfo;
Harald Welte9d810fd2005-08-13 13:56:26 -0700100
Harald Welte2e4e6a12006-01-12 13:30:04 -0800101 if (sinfo->what != XT_CONNBYTES_PKTS &&
102 sinfo->what != XT_CONNBYTES_BYTES &&
103 sinfo->what != XT_CONNBYTES_AVGPKT)
Jan Engelhardtccb79bd2007-07-07 22:16:00 -0700104 return false;
Harald Welte9d810fd2005-08-13 13:56:26 -0700105
Harald Welte2e4e6a12006-01-12 13:30:04 -0800106 if (sinfo->direction != XT_CONNBYTES_DIR_ORIGINAL &&
107 sinfo->direction != XT_CONNBYTES_DIR_REPLY &&
108 sinfo->direction != XT_CONNBYTES_DIR_BOTH)
Jan Engelhardtccb79bd2007-07-07 22:16:00 -0700109 return false;
Harald Welte9d810fd2005-08-13 13:56:26 -0700110
Yasuyuki Kozakai11078c32006-12-12 00:29:02 -0800111 if (nf_ct_l3proto_try_module_get(match->family) < 0) {
112 printk(KERN_WARNING "can't load conntrack support for "
Jan Engelhardtdf54aae2007-12-17 22:43:15 -0800113 "proto=%u\n", match->family);
Jan Engelhardtccb79bd2007-07-07 22:16:00 -0700114 return false;
Yasuyuki Kozakai11078c32006-12-12 00:29:02 -0800115 }
116
Jan Engelhardtccb79bd2007-07-07 22:16:00 -0700117 return true;
Harald Welte9d810fd2005-08-13 13:56:26 -0700118}
119
Yasuyuki Kozakai11078c32006-12-12 00:29:02 -0800120static void
Jan Engelhardtd3c5ee62007-12-04 23:24:03 -0800121connbytes_mt_destroy(const struct xt_match *match, void *matchinfo)
Yasuyuki Kozakai11078c32006-12-12 00:29:02 -0800122{
123 nf_ct_l3proto_module_put(match->family);
124}
125
Jan Engelhardtd3c5ee62007-12-04 23:24:03 -0800126static struct xt_match connbytes_mt_reg[] __read_mostly = {
Patrick McHardy4470bbc2006-08-22 00:34:04 -0700127 {
128 .name = "connbytes",
129 .family = AF_INET,
Jan Engelhardtd3c5ee62007-12-04 23:24:03 -0800130 .checkentry = connbytes_mt_check,
131 .match = connbytes_mt,
132 .destroy = connbytes_mt_destroy,
Patrick McHardy4470bbc2006-08-22 00:34:04 -0700133 .matchsize = sizeof(struct xt_connbytes_info),
134 .me = THIS_MODULE
135 },
136 {
137 .name = "connbytes",
138 .family = AF_INET6,
Jan Engelhardtd3c5ee62007-12-04 23:24:03 -0800139 .checkentry = connbytes_mt_check,
140 .match = connbytes_mt,
141 .destroy = connbytes_mt_destroy,
Patrick McHardy4470bbc2006-08-22 00:34:04 -0700142 .matchsize = sizeof(struct xt_connbytes_info),
143 .me = THIS_MODULE
144 },
Harald Welte9d810fd2005-08-13 13:56:26 -0700145};
146
Jan Engelhardtd3c5ee62007-12-04 23:24:03 -0800147static int __init connbytes_mt_init(void)
Harald Welte9d810fd2005-08-13 13:56:26 -0700148{
Jan Engelhardtd3c5ee62007-12-04 23:24:03 -0800149 return xt_register_matches(connbytes_mt_reg,
150 ARRAY_SIZE(connbytes_mt_reg));
Harald Welte9d810fd2005-08-13 13:56:26 -0700151}
152
Jan Engelhardtd3c5ee62007-12-04 23:24:03 -0800153static void __exit connbytes_mt_exit(void)
Harald Welte9d810fd2005-08-13 13:56:26 -0700154{
Jan Engelhardtd3c5ee62007-12-04 23:24:03 -0800155 xt_unregister_matches(connbytes_mt_reg, ARRAY_SIZE(connbytes_mt_reg));
Harald Welte9d810fd2005-08-13 13:56:26 -0700156}
157
Jan Engelhardtd3c5ee62007-12-04 23:24:03 -0800158module_init(connbytes_mt_init);
159module_exit(connbytes_mt_exit);