blob: 5b138506690ec578105911ffb64309b5297d6458 [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 */
Jan Engelhardt8bee4ba2010-03-17 16:04:40 +01004#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
Harald Welte9d810fd2005-08-13 13:56:26 -07005#include <linux/module.h>
Jiri Slaby1977f032007-10-18 23:40:25 -07006#include <linux/bitops.h>
Harald Welte9d810fd2005-08-13 13:56:26 -07007#include <linux/skbuff.h>
Roman Zippel6f6d6a12008-05-01 04:34:28 -07008#include <linux/math64.h>
Harald Welte2e4e6a12006-01-12 13:30:04 -08009#include <linux/netfilter/x_tables.h>
10#include <linux/netfilter/xt_connbytes.h>
Patrick McHardy587aa642007-03-14 16:37:25 -070011#include <net/netfilter/nf_conntrack.h>
Krzysztof Piotr Oledzki58401572008-07-21 10:01:34 -070012#include <net/netfilter/nf_conntrack_acct.h>
Harald Welte9d810fd2005-08-13 13:56:26 -070013
Harald Welte9d810fd2005-08-13 13:56:26 -070014MODULE_LICENSE("GPL");
15MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
Jan Engelhardt2ae15b62008-01-14 23:42:28 -080016MODULE_DESCRIPTION("Xtables: Number of packets/bytes per connection matching");
Harald Welte2e4e6a12006-01-12 13:30:04 -080017MODULE_ALIAS("ipt_connbytes");
Jan Engelhardt73aaf932007-10-11 14:36:40 -070018MODULE_ALIAS("ip6t_connbytes");
Harald Welte9d810fd2005-08-13 13:56:26 -070019
Jan Engelhardt1d93a9c2007-07-07 22:15:35 -070020static bool
Jan Engelhardt62fc8052009-07-07 20:42:08 +020021connbytes_mt(const struct sk_buff *skb, struct xt_action_param *par)
Harald Welte9d810fd2005-08-13 13:56:26 -070022{
Jan Engelhardtf7108a22008-10-08 11:35:18 +020023 const struct xt_connbytes_info *sinfo = par->matchinfo;
Jan Engelhardta47362a2007-07-07 22:16:55 -070024 const struct nf_conn *ct;
Patrick McHardy587aa642007-03-14 16:37:25 -070025 enum ip_conntrack_info ctinfo;
Harald Welte9d810fd2005-08-13 13:56:26 -070026 u_int64_t what = 0; /* initialize to make gcc happy */
Patrick McHardyfb74a8412007-01-30 14:24:29 -080027 u_int64_t bytes = 0;
28 u_int64_t pkts = 0;
Krzysztof Piotr Oledzki58401572008-07-21 10:01:34 -070029 const struct nf_conn_counter *counters;
Harald Welte9d810fd2005-08-13 13:56:26 -070030
Patrick McHardy587aa642007-03-14 16:37:25 -070031 ct = nf_ct_get(skb, &ctinfo);
32 if (!ct)
Jan Engelhardt1d93a9c2007-07-07 22:15:35 -070033 return false;
Krzysztof Piotr Oledzki58401572008-07-21 10:01:34 -070034
35 counters = nf_conn_acct_find(ct);
36 if (!counters)
37 return false;
Harald Welte9d810fd2005-08-13 13:56:26 -070038
39 switch (sinfo->what) {
Harald Welte2e4e6a12006-01-12 13:30:04 -080040 case XT_CONNBYTES_PKTS:
Harald Welte9d810fd2005-08-13 13:56:26 -070041 switch (sinfo->direction) {
Harald Welte2e4e6a12006-01-12 13:30:04 -080042 case XT_CONNBYTES_DIR_ORIGINAL:
Yasuyuki Kozakai9fb9cbb2005-11-09 16:38:16 -080043 what = counters[IP_CT_DIR_ORIGINAL].packets;
Harald Welte9d810fd2005-08-13 13:56:26 -070044 break;
Harald Welte2e4e6a12006-01-12 13:30:04 -080045 case XT_CONNBYTES_DIR_REPLY:
Yasuyuki Kozakai9fb9cbb2005-11-09 16:38:16 -080046 what = counters[IP_CT_DIR_REPLY].packets;
Harald Welte9d810fd2005-08-13 13:56:26 -070047 break;
Harald Welte2e4e6a12006-01-12 13:30:04 -080048 case XT_CONNBYTES_DIR_BOTH:
Yasuyuki Kozakai9fb9cbb2005-11-09 16:38:16 -080049 what = counters[IP_CT_DIR_ORIGINAL].packets;
50 what += counters[IP_CT_DIR_REPLY].packets;
Harald Welte9d810fd2005-08-13 13:56:26 -070051 break;
52 }
53 break;
Harald Welte2e4e6a12006-01-12 13:30:04 -080054 case XT_CONNBYTES_BYTES:
Harald Welte9d810fd2005-08-13 13:56:26 -070055 switch (sinfo->direction) {
Harald Welte2e4e6a12006-01-12 13:30:04 -080056 case XT_CONNBYTES_DIR_ORIGINAL:
Yasuyuki Kozakai9fb9cbb2005-11-09 16:38:16 -080057 what = counters[IP_CT_DIR_ORIGINAL].bytes;
Harald Welte9d810fd2005-08-13 13:56:26 -070058 break;
Harald Welte2e4e6a12006-01-12 13:30:04 -080059 case XT_CONNBYTES_DIR_REPLY:
Yasuyuki Kozakai9fb9cbb2005-11-09 16:38:16 -080060 what = counters[IP_CT_DIR_REPLY].bytes;
Harald Welte9d810fd2005-08-13 13:56:26 -070061 break;
Harald Welte2e4e6a12006-01-12 13:30:04 -080062 case XT_CONNBYTES_DIR_BOTH:
Yasuyuki Kozakai9fb9cbb2005-11-09 16:38:16 -080063 what = counters[IP_CT_DIR_ORIGINAL].bytes;
64 what += counters[IP_CT_DIR_REPLY].bytes;
Harald Welte9d810fd2005-08-13 13:56:26 -070065 break;
66 }
67 break;
Harald Welte2e4e6a12006-01-12 13:30:04 -080068 case XT_CONNBYTES_AVGPKT:
Harald Welte9d810fd2005-08-13 13:56:26 -070069 switch (sinfo->direction) {
Harald Welte2e4e6a12006-01-12 13:30:04 -080070 case XT_CONNBYTES_DIR_ORIGINAL:
Patrick McHardyfb74a8412007-01-30 14:24:29 -080071 bytes = counters[IP_CT_DIR_ORIGINAL].bytes;
72 pkts = counters[IP_CT_DIR_ORIGINAL].packets;
Harald Welte9d810fd2005-08-13 13:56:26 -070073 break;
Harald Welte2e4e6a12006-01-12 13:30:04 -080074 case XT_CONNBYTES_DIR_REPLY:
Patrick McHardyfb74a8412007-01-30 14:24:29 -080075 bytes = counters[IP_CT_DIR_REPLY].bytes;
76 pkts = counters[IP_CT_DIR_REPLY].packets;
Harald Welte9d810fd2005-08-13 13:56:26 -070077 break;
Harald Welte2e4e6a12006-01-12 13:30:04 -080078 case XT_CONNBYTES_DIR_BOTH:
Patrick McHardyfb74a8412007-01-30 14:24:29 -080079 bytes = counters[IP_CT_DIR_ORIGINAL].bytes +
80 counters[IP_CT_DIR_REPLY].bytes;
81 pkts = counters[IP_CT_DIR_ORIGINAL].packets +
82 counters[IP_CT_DIR_REPLY].packets;
Harald Welte9d810fd2005-08-13 13:56:26 -070083 break;
84 }
Patrick McHardyfb74a8412007-01-30 14:24:29 -080085 if (pkts != 0)
Roman Zippel6f6d6a12008-05-01 04:34:28 -070086 what = div64_u64(bytes, pkts);
Harald Welte9d810fd2005-08-13 13:56:26 -070087 break;
88 }
89
90 if (sinfo->count.to)
Jan Engelhardt7c4e36b2007-07-07 22:19:08 -070091 return what <= sinfo->count.to && what >= sinfo->count.from;
Harald Welte9d810fd2005-08-13 13:56:26 -070092 else
Jan Engelhardt7c4e36b2007-07-07 22:19:08 -070093 return what >= sinfo->count.from;
Harald Welte9d810fd2005-08-13 13:56:26 -070094}
95
Jan Engelhardtb0f38452010-03-19 17:16:42 +010096static int connbytes_mt_check(const struct xt_mtchk_param *par)
Harald Welte9d810fd2005-08-13 13:56:26 -070097{
Jan Engelhardt9b4fce72008-10-08 11:35:18 +020098 const struct xt_connbytes_info *sinfo = par->matchinfo;
Jan Engelhardt4a5a5c72010-03-19 17:32:59 +010099 int ret;
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 Engelhardtbd414ee2010-03-23 16:35:56 +0100104 return -EINVAL;
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 Engelhardtbd414ee2010-03-23 16:35:56 +0100109 return -EINVAL;
Harald Welte9d810fd2005-08-13 13:56:26 -0700110
Jan Engelhardt4a5a5c72010-03-19 17:32:59 +0100111 ret = nf_ct_l3proto_try_module_get(par->family);
Jan Engelhardtf95c74e2010-03-21 04:05:56 +0100112 if (ret < 0)
Jan Engelhardt8bee4ba2010-03-17 16:04:40 +0100113 pr_info("cannot load conntrack support for proto=%u\n",
114 par->family);
Tim Gardnera8756202010-06-25 14:44:07 +0200115
116 /*
117 * This filter cannot function correctly unless connection tracking
118 * accounting is enabled, so complain in the hope that someone notices.
119 */
120 if (!nf_ct_acct_enabled(par->net)) {
121 pr_warning("Forcing CT accounting to be enabled\n");
122 nf_ct_set_acct(par->net, true);
123 }
124
Jan Engelhardtf95c74e2010-03-21 04:05:56 +0100125 return ret;
Harald Welte9d810fd2005-08-13 13:56:26 -0700126}
127
Jan Engelhardt6be3d852008-10-08 11:35:19 +0200128static void connbytes_mt_destroy(const struct xt_mtdtor_param *par)
Yasuyuki Kozakai11078c32006-12-12 00:29:02 -0800129{
Jan Engelhardt92f3b2b2008-10-08 11:35:20 +0200130 nf_ct_l3proto_module_put(par->family);
Yasuyuki Kozakai11078c32006-12-12 00:29:02 -0800131}
132
Jan Engelhardt92f3b2b2008-10-08 11:35:20 +0200133static struct xt_match connbytes_mt_reg __read_mostly = {
134 .name = "connbytes",
135 .revision = 0,
136 .family = NFPROTO_UNSPEC,
137 .checkentry = connbytes_mt_check,
138 .match = connbytes_mt,
139 .destroy = connbytes_mt_destroy,
140 .matchsize = sizeof(struct xt_connbytes_info),
141 .me = THIS_MODULE,
Harald Welte9d810fd2005-08-13 13:56:26 -0700142};
143
Jan Engelhardtd3c5ee62007-12-04 23:24:03 -0800144static int __init connbytes_mt_init(void)
Harald Welte9d810fd2005-08-13 13:56:26 -0700145{
Jan Engelhardt92f3b2b2008-10-08 11:35:20 +0200146 return xt_register_match(&connbytes_mt_reg);
Harald Welte9d810fd2005-08-13 13:56:26 -0700147}
148
Jan Engelhardtd3c5ee62007-12-04 23:24:03 -0800149static void __exit connbytes_mt_exit(void)
Harald Welte9d810fd2005-08-13 13:56:26 -0700150{
Jan Engelhardt92f3b2b2008-10-08 11:35:20 +0200151 xt_unregister_match(&connbytes_mt_reg);
Harald Welte9d810fd2005-08-13 13:56:26 -0700152}
153
Jan Engelhardtd3c5ee62007-12-04 23:24:03 -0800154module_init(connbytes_mt_init);
155module_exit(connbytes_mt_exit);