blob: d4bec261e74e636e5a51c8ea95480f15bc61a1ab [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;
Holger Eitzenbergerf7b13e42013-09-26 17:31:51 +020029 const struct nf_conn_acct *acct;
Krzysztof Piotr Oledzki58401572008-07-21 10:01:34 -070030 const struct nf_conn_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;
Krzysztof Piotr Oledzki58401572008-07-21 10:01:34 -070035
Holger Eitzenbergerf7b13e42013-09-26 17:31:51 +020036 acct = nf_conn_acct_find(ct);
37 if (!acct)
Krzysztof Piotr Oledzki58401572008-07-21 10:01:34 -070038 return false;
Harald Welte9d810fd2005-08-13 13:56:26 -070039
Holger Eitzenbergerf7b13e42013-09-26 17:31:51 +020040 counters = acct->counter;
Harald Welte9d810fd2005-08-13 13:56:26 -070041 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:
Eric Dumazetb3e0bfa2011-12-14 14:45:20 +010045 what = atomic64_read(&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:
Eric Dumazetb3e0bfa2011-12-14 14:45:20 +010048 what = atomic64_read(&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:
Eric Dumazetb3e0bfa2011-12-14 14:45:20 +010051 what = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].packets);
52 what += atomic64_read(&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:
Eric Dumazetb3e0bfa2011-12-14 14:45:20 +010059 what = atomic64_read(&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:
Eric Dumazetb3e0bfa2011-12-14 14:45:20 +010062 what = atomic64_read(&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:
Eric Dumazetb3e0bfa2011-12-14 14:45:20 +010065 what = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].bytes);
66 what += atomic64_read(&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:
Eric Dumazetb3e0bfa2011-12-14 14:45:20 +010073 bytes = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].bytes);
74 pkts = atomic64_read(&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:
Eric Dumazetb3e0bfa2011-12-14 14:45:20 +010077 bytes = atomic64_read(&counters[IP_CT_DIR_REPLY].bytes);
78 pkts = atomic64_read(&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:
Eric Dumazetb3e0bfa2011-12-14 14:45:20 +010081 bytes = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].bytes) +
82 atomic64_read(&counters[IP_CT_DIR_REPLY].bytes);
83 pkts = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].packets) +
84 atomic64_read(&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)
Roman Zippel6f6d6a12008-05-01 04:34:28 -070088 what = div64_u64(bytes, pkts);
Harald Welte9d810fd2005-08-13 13:56:26 -070089 break;
90 }
91
Florian Westphal0354b482011-12-16 18:35:15 +010092 if (sinfo->count.to >= sinfo->count.from)
Jan Engelhardt7c4e36b2007-07-07 22:19:08 -070093 return what <= sinfo->count.to && what >= sinfo->count.from;
Florian Westphal0354b482011-12-16 18:35:15 +010094 else /* inverted */
95 return what < sinfo->count.to || what > sinfo->count.from;
Harald Welte9d810fd2005-08-13 13:56:26 -070096}
97
Jan Engelhardtb0f38452010-03-19 17:16:42 +010098static int connbytes_mt_check(const struct xt_mtchk_param *par)
Harald Welte9d810fd2005-08-13 13:56:26 -070099{
Jan Engelhardt9b4fce72008-10-08 11:35:18 +0200100 const struct xt_connbytes_info *sinfo = par->matchinfo;
Jan Engelhardt4a5a5c72010-03-19 17:32:59 +0100101 int ret;
Harald Welte9d810fd2005-08-13 13:56:26 -0700102
Harald Welte2e4e6a12006-01-12 13:30:04 -0800103 if (sinfo->what != XT_CONNBYTES_PKTS &&
104 sinfo->what != XT_CONNBYTES_BYTES &&
105 sinfo->what != XT_CONNBYTES_AVGPKT)
Jan Engelhardtbd414ee2010-03-23 16:35:56 +0100106 return -EINVAL;
Harald Welte9d810fd2005-08-13 13:56:26 -0700107
Harald Welte2e4e6a12006-01-12 13:30:04 -0800108 if (sinfo->direction != XT_CONNBYTES_DIR_ORIGINAL &&
109 sinfo->direction != XT_CONNBYTES_DIR_REPLY &&
110 sinfo->direction != XT_CONNBYTES_DIR_BOTH)
Jan Engelhardtbd414ee2010-03-23 16:35:56 +0100111 return -EINVAL;
Harald Welte9d810fd2005-08-13 13:56:26 -0700112
Jan Engelhardt4a5a5c72010-03-19 17:32:59 +0100113 ret = nf_ct_l3proto_try_module_get(par->family);
Jan Engelhardtf95c74e2010-03-21 04:05:56 +0100114 if (ret < 0)
Jan Engelhardt8bee4ba2010-03-17 16:04:40 +0100115 pr_info("cannot load conntrack support for proto=%u\n",
116 par->family);
Tim Gardnera8756202010-06-25 14:44:07 +0200117
118 /*
119 * This filter cannot function correctly unless connection tracking
120 * accounting is enabled, so complain in the hope that someone notices.
121 */
122 if (!nf_ct_acct_enabled(par->net)) {
Joe Perchesb167a372014-09-09 21:17:32 -0700123 pr_warn("Forcing CT accounting to be enabled\n");
Tim Gardnera8756202010-06-25 14:44:07 +0200124 nf_ct_set_acct(par->net, true);
125 }
126
Jan Engelhardtf95c74e2010-03-21 04:05:56 +0100127 return ret;
Harald Welte9d810fd2005-08-13 13:56:26 -0700128}
129
Jan Engelhardt6be3d852008-10-08 11:35:19 +0200130static void connbytes_mt_destroy(const struct xt_mtdtor_param *par)
Yasuyuki Kozakai11078c32006-12-12 00:29:02 -0800131{
Jan Engelhardt92f3b2b2008-10-08 11:35:20 +0200132 nf_ct_l3proto_module_put(par->family);
Yasuyuki Kozakai11078c32006-12-12 00:29:02 -0800133}
134
Jan Engelhardt92f3b2b2008-10-08 11:35:20 +0200135static struct xt_match connbytes_mt_reg __read_mostly = {
136 .name = "connbytes",
137 .revision = 0,
138 .family = NFPROTO_UNSPEC,
139 .checkentry = connbytes_mt_check,
140 .match = connbytes_mt,
141 .destroy = connbytes_mt_destroy,
142 .matchsize = sizeof(struct xt_connbytes_info),
143 .me = THIS_MODULE,
Harald Welte9d810fd2005-08-13 13:56:26 -0700144};
145
Jan Engelhardtd3c5ee62007-12-04 23:24:03 -0800146static int __init connbytes_mt_init(void)
Harald Welte9d810fd2005-08-13 13:56:26 -0700147{
Jan Engelhardt92f3b2b2008-10-08 11:35:20 +0200148 return xt_register_match(&connbytes_mt_reg);
Harald Welte9d810fd2005-08-13 13:56:26 -0700149}
150
Jan Engelhardtd3c5ee62007-12-04 23:24:03 -0800151static void __exit connbytes_mt_exit(void)
Harald Welte9d810fd2005-08-13 13:56:26 -0700152{
Jan Engelhardt92f3b2b2008-10-08 11:35:20 +0200153 xt_unregister_match(&connbytes_mt_reg);
Harald Welte9d810fd2005-08-13 13:56:26 -0700154}
155
Jan Engelhardtd3c5ee62007-12-04 23:24:03 -0800156module_init(connbytes_mt_init);
157module_exit(connbytes_mt_exit);