blob: 9ec50139b9a177d559236790b3f0351c7ba9ef71 [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>
Harald Welte2e4e6a12006-01-12 13:30:04 -08007#include <linux/netfilter/x_tables.h>
8#include <linux/netfilter/xt_connbytes.h>
Patrick McHardy587aa642007-03-14 16:37:25 -07009#include <net/netfilter/nf_conntrack.h>
Harald Welte9d810fd2005-08-13 13:56:26 -070010
11#include <asm/div64.h>
Harald Welte9d810fd2005-08-13 13:56:26 -070012
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");
Jan Engelhardt73aaf932007-10-11 14:36:40 -070017MODULE_ALIAS("ip6t_connbytes");
Harald Welte9d810fd2005-08-13 13:56:26 -070018
Jan Engelhardt1d93a9c2007-07-07 22:15:35 -070019static bool
Harald Welte9d810fd2005-08-13 13:56:26 -070020match(const struct sk_buff *skb,
21 const struct net_device *in,
22 const struct net_device *out,
Patrick McHardyc4986732006-03-20 18:02:56 -080023 const struct xt_match *match,
Harald Welte9d810fd2005-08-13 13:56:26 -070024 const void *matchinfo,
25 int offset,
Harald Welte2e4e6a12006-01-12 13:30:04 -080026 unsigned int protoff,
Jan Engelhardtcff533a2007-07-07 22:15:12 -070027 bool *hotdrop)
Harald Welte9d810fd2005-08-13 13:56:26 -070028{
Harald Welte2e4e6a12006-01-12 13:30:04 -080029 const struct xt_connbytes_info *sinfo = matchinfo;
Jan Engelhardta47362a2007-07-07 22:16:55 -070030 const struct nf_conn *ct;
Patrick McHardy587aa642007-03-14 16:37:25 -070031 enum ip_conntrack_info ctinfo;
Harald Welte9d810fd2005-08-13 13:56:26 -070032 u_int64_t what = 0; /* initialize to make gcc happy */
Patrick McHardyfb74a8412007-01-30 14:24:29 -080033 u_int64_t bytes = 0;
34 u_int64_t pkts = 0;
Yasuyuki Kozakai9fb9cbb2005-11-09 16:38:16 -080035 const struct ip_conntrack_counter *counters;
Harald Welte9d810fd2005-08-13 13:56:26 -070036
Patrick McHardy587aa642007-03-14 16:37:25 -070037 ct = nf_ct_get(skb, &ctinfo);
38 if (!ct)
Jan Engelhardt1d93a9c2007-07-07 22:15:35 -070039 return false;
Patrick McHardy587aa642007-03-14 16:37:25 -070040 counters = ct->counters;
Harald Welte9d810fd2005-08-13 13:56:26 -070041
42 switch (sinfo->what) {
Harald Welte2e4e6a12006-01-12 13:30:04 -080043 case XT_CONNBYTES_PKTS:
Harald Welte9d810fd2005-08-13 13:56:26 -070044 switch (sinfo->direction) {
Harald Welte2e4e6a12006-01-12 13:30:04 -080045 case XT_CONNBYTES_DIR_ORIGINAL:
Yasuyuki Kozakai9fb9cbb2005-11-09 16:38:16 -080046 what = counters[IP_CT_DIR_ORIGINAL].packets;
Harald Welte9d810fd2005-08-13 13:56:26 -070047 break;
Harald Welte2e4e6a12006-01-12 13:30:04 -080048 case XT_CONNBYTES_DIR_REPLY:
Yasuyuki Kozakai9fb9cbb2005-11-09 16:38:16 -080049 what = counters[IP_CT_DIR_REPLY].packets;
Harald Welte9d810fd2005-08-13 13:56:26 -070050 break;
Harald Welte2e4e6a12006-01-12 13:30:04 -080051 case XT_CONNBYTES_DIR_BOTH:
Yasuyuki Kozakai9fb9cbb2005-11-09 16:38:16 -080052 what = counters[IP_CT_DIR_ORIGINAL].packets;
53 what += counters[IP_CT_DIR_REPLY].packets;
Harald Welte9d810fd2005-08-13 13:56:26 -070054 break;
55 }
56 break;
Harald Welte2e4e6a12006-01-12 13:30:04 -080057 case XT_CONNBYTES_BYTES:
Harald Welte9d810fd2005-08-13 13:56:26 -070058 switch (sinfo->direction) {
Harald Welte2e4e6a12006-01-12 13:30:04 -080059 case XT_CONNBYTES_DIR_ORIGINAL:
Yasuyuki Kozakai9fb9cbb2005-11-09 16:38:16 -080060 what = counters[IP_CT_DIR_ORIGINAL].bytes;
Harald Welte9d810fd2005-08-13 13:56:26 -070061 break;
Harald Welte2e4e6a12006-01-12 13:30:04 -080062 case XT_CONNBYTES_DIR_REPLY:
Yasuyuki Kozakai9fb9cbb2005-11-09 16:38:16 -080063 what = counters[IP_CT_DIR_REPLY].bytes;
Harald Welte9d810fd2005-08-13 13:56:26 -070064 break;
Harald Welte2e4e6a12006-01-12 13:30:04 -080065 case XT_CONNBYTES_DIR_BOTH:
Yasuyuki Kozakai9fb9cbb2005-11-09 16:38:16 -080066 what = counters[IP_CT_DIR_ORIGINAL].bytes;
67 what += counters[IP_CT_DIR_REPLY].bytes;
Harald Welte9d810fd2005-08-13 13:56:26 -070068 break;
69 }
70 break;
Harald Welte2e4e6a12006-01-12 13:30:04 -080071 case XT_CONNBYTES_AVGPKT:
Harald Welte9d810fd2005-08-13 13:56:26 -070072 switch (sinfo->direction) {
Harald Welte2e4e6a12006-01-12 13:30:04 -080073 case XT_CONNBYTES_DIR_ORIGINAL:
Patrick McHardyfb74a8412007-01-30 14:24:29 -080074 bytes = counters[IP_CT_DIR_ORIGINAL].bytes;
75 pkts = counters[IP_CT_DIR_ORIGINAL].packets;
Harald Welte9d810fd2005-08-13 13:56:26 -070076 break;
Harald Welte2e4e6a12006-01-12 13:30:04 -080077 case XT_CONNBYTES_DIR_REPLY:
Patrick McHardyfb74a8412007-01-30 14:24:29 -080078 bytes = counters[IP_CT_DIR_REPLY].bytes;
79 pkts = counters[IP_CT_DIR_REPLY].packets;
Harald Welte9d810fd2005-08-13 13:56:26 -070080 break;
Harald Welte2e4e6a12006-01-12 13:30:04 -080081 case XT_CONNBYTES_DIR_BOTH:
Patrick McHardyfb74a8412007-01-30 14:24:29 -080082 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;
Harald Welte9d810fd2005-08-13 13:56:26 -070086 break;
87 }
Patrick McHardyfb74a8412007-01-30 14:24:29 -080088 if (pkts != 0)
89 what = div64_64(bytes, pkts);
Harald Welte9d810fd2005-08-13 13:56:26 -070090 break;
91 }
92
93 if (sinfo->count.to)
Jan Engelhardt7c4e36b2007-07-07 22:19:08 -070094 return what <= sinfo->count.to && what >= sinfo->count.from;
Harald Welte9d810fd2005-08-13 13:56:26 -070095 else
Jan Engelhardt7c4e36b2007-07-07 22:19:08 -070096 return what >= sinfo->count.from;
Harald Welte9d810fd2005-08-13 13:56:26 -070097}
98
Jan Engelhardtccb79bd2007-07-07 22:16:00 -070099static bool check(const char *tablename,
100 const void *ip,
101 const struct xt_match *match,
102 void *matchinfo,
103 unsigned int hook_mask)
Harald Welte9d810fd2005-08-13 13:56:26 -0700104{
Harald Welte2e4e6a12006-01-12 13:30:04 -0800105 const struct xt_connbytes_info *sinfo = matchinfo;
Harald Welte9d810fd2005-08-13 13:56:26 -0700106
Harald Welte2e4e6a12006-01-12 13:30:04 -0800107 if (sinfo->what != XT_CONNBYTES_PKTS &&
108 sinfo->what != XT_CONNBYTES_BYTES &&
109 sinfo->what != XT_CONNBYTES_AVGPKT)
Jan Engelhardtccb79bd2007-07-07 22:16:00 -0700110 return false;
Harald Welte9d810fd2005-08-13 13:56:26 -0700111
Harald Welte2e4e6a12006-01-12 13:30:04 -0800112 if (sinfo->direction != XT_CONNBYTES_DIR_ORIGINAL &&
113 sinfo->direction != XT_CONNBYTES_DIR_REPLY &&
114 sinfo->direction != XT_CONNBYTES_DIR_BOTH)
Jan Engelhardtccb79bd2007-07-07 22:16:00 -0700115 return false;
Harald Welte9d810fd2005-08-13 13:56:26 -0700116
Yasuyuki Kozakai11078c32006-12-12 00:29:02 -0800117 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);
Jan Engelhardtccb79bd2007-07-07 22:16:00 -0700120 return false;
Yasuyuki Kozakai11078c32006-12-12 00:29:02 -0800121 }
122
Jan Engelhardtccb79bd2007-07-07 22:16:00 -0700123 return true;
Harald Welte9d810fd2005-08-13 13:56:26 -0700124}
125
Yasuyuki Kozakai11078c32006-12-12 00:29:02 -0800126static void
127destroy(const struct xt_match *match, void *matchinfo)
128{
129 nf_ct_l3proto_module_put(match->family);
130}
131
Patrick McHardy9f15c532007-07-07 22:22:02 -0700132static struct xt_match xt_connbytes_match[] __read_mostly = {
Patrick McHardy4470bbc2006-08-22 00:34:04 -0700133 {
134 .name = "connbytes",
135 .family = AF_INET,
136 .checkentry = check,
137 .match = match,
Yasuyuki Kozakai11078c32006-12-12 00:29:02 -0800138 .destroy = destroy,
Patrick McHardy4470bbc2006-08-22 00:34:04 -0700139 .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,
Yasuyuki Kozakai11078c32006-12-12 00:29:02 -0800147 .destroy = destroy,
Patrick McHardy4470bbc2006-08-22 00:34:04 -0700148 .matchsize = sizeof(struct xt_connbytes_info),
149 .me = THIS_MODULE
150 },
Harald Welte9d810fd2005-08-13 13:56:26 -0700151};
152
Andrew Morton65b4b4e2006-03-28 16:37:06 -0800153static int __init xt_connbytes_init(void)
Harald Welte9d810fd2005-08-13 13:56:26 -0700154{
Patrick McHardy4470bbc2006-08-22 00:34:04 -0700155 return xt_register_matches(xt_connbytes_match,
156 ARRAY_SIZE(xt_connbytes_match));
Harald Welte9d810fd2005-08-13 13:56:26 -0700157}
158
Andrew Morton65b4b4e2006-03-28 16:37:06 -0800159static void __exit xt_connbytes_fini(void)
Harald Welte9d810fd2005-08-13 13:56:26 -0700160{
Patrick McHardy4470bbc2006-08-22 00:34:04 -0700161 xt_unregister_matches(xt_connbytes_match,
162 ARRAY_SIZE(xt_connbytes_match));
Harald Welte9d810fd2005-08-13 13:56:26 -0700163}
164
Andrew Morton65b4b4e2006-03-28 16:37:06 -0800165module_init(xt_connbytes_init);
166module_exit(xt_connbytes_fini);