xref: /openbmc/linux/net/netfilter/xt_connbytes.c (revision b2606644)
12e4e6a17SHarald Welte /* Kernel module to match connection tracking byte counter.
22e4e6a17SHarald Welte  * GPL (C) 2002 Martin Devera (devik@cdi.cz).
32e4e6a17SHarald Welte  */
48bee4badSJan Engelhardt #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
52e4e6a17SHarald Welte #include <linux/module.h>
61977f032SJiri Slaby #include <linux/bitops.h>
72e4e6a17SHarald Welte #include <linux/skbuff.h>
86f6d6a1aSRoman Zippel #include <linux/math64.h>
92e4e6a17SHarald Welte #include <linux/netfilter/x_tables.h>
102e4e6a17SHarald Welte #include <linux/netfilter/xt_connbytes.h>
11587aa641SPatrick McHardy #include <net/netfilter/nf_conntrack.h>
1258401572SKrzysztof Piotr Oledzki #include <net/netfilter/nf_conntrack_acct.h>
132e4e6a17SHarald Welte 
142e4e6a17SHarald Welte MODULE_LICENSE("GPL");
152e4e6a17SHarald Welte MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
162ae15b64SJan Engelhardt MODULE_DESCRIPTION("Xtables: Number of packets/bytes per connection matching");
172e4e6a17SHarald Welte MODULE_ALIAS("ipt_connbytes");
1873aaf935SJan Engelhardt MODULE_ALIAS("ip6t_connbytes");
192e4e6a17SHarald Welte 
201d93a9cbSJan Engelhardt static bool
connbytes_mt(const struct sk_buff * skb,struct xt_action_param * par)2162fc8051SJan Engelhardt connbytes_mt(const struct sk_buff *skb, struct xt_action_param *par)
222e4e6a17SHarald Welte {
23f7108a20SJan Engelhardt 	const struct xt_connbytes_info *sinfo = par->matchinfo;
24a47362a2SJan Engelhardt 	const struct nf_conn *ct;
25587aa641SPatrick McHardy 	enum ip_conntrack_info ctinfo;
262e4e6a17SHarald Welte 	u_int64_t what = 0;	/* initialize to make gcc happy */
27fb74a841SPatrick McHardy 	u_int64_t bytes = 0;
28fb74a841SPatrick McHardy 	u_int64_t pkts = 0;
29f7b13e43SHolger Eitzenberger 	const struct nf_conn_acct *acct;
3058401572SKrzysztof Piotr Oledzki 	const struct nf_conn_counter *counters;
312e4e6a17SHarald Welte 
32587aa641SPatrick McHardy 	ct = nf_ct_get(skb, &ctinfo);
33587aa641SPatrick McHardy 	if (!ct)
341d93a9cbSJan Engelhardt 		return false;
3558401572SKrzysztof Piotr Oledzki 
36f7b13e43SHolger Eitzenberger 	acct = nf_conn_acct_find(ct);
37f7b13e43SHolger Eitzenberger 	if (!acct)
3858401572SKrzysztof Piotr Oledzki 		return false;
392e4e6a17SHarald Welte 
40f7b13e43SHolger Eitzenberger 	counters = acct->counter;
412e4e6a17SHarald Welte 	switch (sinfo->what) {
422e4e6a17SHarald Welte 	case XT_CONNBYTES_PKTS:
432e4e6a17SHarald Welte 		switch (sinfo->direction) {
442e4e6a17SHarald Welte 		case XT_CONNBYTES_DIR_ORIGINAL:
45b3e0bfa7SEric Dumazet 			what = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].packets);
462e4e6a17SHarald Welte 			break;
472e4e6a17SHarald Welte 		case XT_CONNBYTES_DIR_REPLY:
48b3e0bfa7SEric Dumazet 			what = atomic64_read(&counters[IP_CT_DIR_REPLY].packets);
492e4e6a17SHarald Welte 			break;
502e4e6a17SHarald Welte 		case XT_CONNBYTES_DIR_BOTH:
51b3e0bfa7SEric Dumazet 			what = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].packets);
52b3e0bfa7SEric Dumazet 			what += atomic64_read(&counters[IP_CT_DIR_REPLY].packets);
532e4e6a17SHarald Welte 			break;
542e4e6a17SHarald Welte 		}
552e4e6a17SHarald Welte 		break;
562e4e6a17SHarald Welte 	case XT_CONNBYTES_BYTES:
572e4e6a17SHarald Welte 		switch (sinfo->direction) {
582e4e6a17SHarald Welte 		case XT_CONNBYTES_DIR_ORIGINAL:
59b3e0bfa7SEric Dumazet 			what = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].bytes);
602e4e6a17SHarald Welte 			break;
612e4e6a17SHarald Welte 		case XT_CONNBYTES_DIR_REPLY:
62b3e0bfa7SEric Dumazet 			what = atomic64_read(&counters[IP_CT_DIR_REPLY].bytes);
632e4e6a17SHarald Welte 			break;
642e4e6a17SHarald Welte 		case XT_CONNBYTES_DIR_BOTH:
65b3e0bfa7SEric Dumazet 			what = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].bytes);
66b3e0bfa7SEric Dumazet 			what += atomic64_read(&counters[IP_CT_DIR_REPLY].bytes);
672e4e6a17SHarald Welte 			break;
682e4e6a17SHarald Welte 		}
692e4e6a17SHarald Welte 		break;
702e4e6a17SHarald Welte 	case XT_CONNBYTES_AVGPKT:
712e4e6a17SHarald Welte 		switch (sinfo->direction) {
722e4e6a17SHarald Welte 		case XT_CONNBYTES_DIR_ORIGINAL:
73b3e0bfa7SEric Dumazet 			bytes = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].bytes);
74b3e0bfa7SEric Dumazet 			pkts  = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].packets);
752e4e6a17SHarald Welte 			break;
762e4e6a17SHarald Welte 		case XT_CONNBYTES_DIR_REPLY:
77b3e0bfa7SEric Dumazet 			bytes = atomic64_read(&counters[IP_CT_DIR_REPLY].bytes);
78b3e0bfa7SEric Dumazet 			pkts  = atomic64_read(&counters[IP_CT_DIR_REPLY].packets);
792e4e6a17SHarald Welte 			break;
802e4e6a17SHarald Welte 		case XT_CONNBYTES_DIR_BOTH:
81b3e0bfa7SEric Dumazet 			bytes = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].bytes) +
82b3e0bfa7SEric Dumazet 				atomic64_read(&counters[IP_CT_DIR_REPLY].bytes);
83b3e0bfa7SEric Dumazet 			pkts  = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].packets) +
84b3e0bfa7SEric Dumazet 				atomic64_read(&counters[IP_CT_DIR_REPLY].packets);
852e4e6a17SHarald Welte 			break;
862e4e6a17SHarald Welte 		}
87fb74a841SPatrick McHardy 		if (pkts != 0)
886f6d6a1aSRoman Zippel 			what = div64_u64(bytes, pkts);
892e4e6a17SHarald Welte 		break;
902e4e6a17SHarald Welte 	}
912e4e6a17SHarald Welte 
920354b48fSFlorian Westphal 	if (sinfo->count.to >= sinfo->count.from)
937c4e36bcSJan Engelhardt 		return what <= sinfo->count.to && what >= sinfo->count.from;
940354b48fSFlorian Westphal 	else /* inverted */
950354b48fSFlorian Westphal 		return what < sinfo->count.to || what > sinfo->count.from;
962e4e6a17SHarald Welte }
972e4e6a17SHarald Welte 
connbytes_mt_check(const struct xt_mtchk_param * par)98b0f38452SJan Engelhardt static int connbytes_mt_check(const struct xt_mtchk_param *par)
992e4e6a17SHarald Welte {
1009b4fce7aSJan Engelhardt 	const struct xt_connbytes_info *sinfo = par->matchinfo;
1014a5a5c73SJan Engelhardt 	int ret;
1022e4e6a17SHarald Welte 
1032e4e6a17SHarald Welte 	if (sinfo->what != XT_CONNBYTES_PKTS &&
1042e4e6a17SHarald Welte 	    sinfo->what != XT_CONNBYTES_BYTES &&
1052e4e6a17SHarald Welte 	    sinfo->what != XT_CONNBYTES_AVGPKT)
106bd414ee6SJan Engelhardt 		return -EINVAL;
1072e4e6a17SHarald Welte 
1082e4e6a17SHarald Welte 	if (sinfo->direction != XT_CONNBYTES_DIR_ORIGINAL &&
1092e4e6a17SHarald Welte 	    sinfo->direction != XT_CONNBYTES_DIR_REPLY &&
1102e4e6a17SHarald Welte 	    sinfo->direction != XT_CONNBYTES_DIR_BOTH)
111bd414ee6SJan Engelhardt 		return -EINVAL;
1122e4e6a17SHarald Welte 
113ecb2421bSFlorian Westphal 	ret = nf_ct_netns_get(par->net, par->family);
114f95c74e3SJan Engelhardt 	if (ret < 0)
115b2606644SFlorian Westphal 		pr_info_ratelimited("cannot load conntrack support for proto=%u\n",
1168bee4badSJan Engelhardt 				    par->family);
117a8756201STim Gardner 
118a8756201STim Gardner 	/*
119a8756201STim Gardner 	 * This filter cannot function correctly unless connection tracking
120a8756201STim Gardner 	 * accounting is enabled, so complain in the hope that someone notices.
121a8756201STim Gardner 	 */
122a8756201STim Gardner 	if (!nf_ct_acct_enabled(par->net)) {
123b167a37cSJoe Perches 		pr_warn("Forcing CT accounting to be enabled\n");
124a8756201STim Gardner 		nf_ct_set_acct(par->net, true);
125a8756201STim Gardner 	}
126a8756201STim Gardner 
1274a5a5c73SJan Engelhardt 	return ret;
12811078c37SYasuyuki Kozakai }
12911078c37SYasuyuki Kozakai 
connbytes_mt_destroy(const struct xt_mtdtor_param * par)1306be3d859SJan Engelhardt static void connbytes_mt_destroy(const struct xt_mtdtor_param *par)
13111078c37SYasuyuki Kozakai {
132ecb2421bSFlorian Westphal 	nf_ct_netns_put(par->net, par->family);
13311078c37SYasuyuki Kozakai }
13411078c37SYasuyuki Kozakai 
13592f3b2b1SJan Engelhardt static struct xt_match connbytes_mt_reg __read_mostly = {
1362e4e6a17SHarald Welte 	.name       = "connbytes",
13792f3b2b1SJan Engelhardt 	.revision   = 0,
13892f3b2b1SJan Engelhardt 	.family     = NFPROTO_UNSPEC,
139d3c5ee6dSJan Engelhardt 	.checkentry = connbytes_mt_check,
140d3c5ee6dSJan Engelhardt 	.match      = connbytes_mt,
141d3c5ee6dSJan Engelhardt 	.destroy    = connbytes_mt_destroy,
1425d04bff0SPatrick McHardy 	.matchsize  = sizeof(struct xt_connbytes_info),
14392f3b2b1SJan Engelhardt 	.me         = THIS_MODULE,
1442e4e6a17SHarald Welte };
1452e4e6a17SHarald Welte 
connbytes_mt_init(void)146d3c5ee6dSJan Engelhardt static int __init connbytes_mt_init(void)
1472e4e6a17SHarald Welte {
14892f3b2b1SJan Engelhardt 	return xt_register_match(&connbytes_mt_reg);
1492e4e6a17SHarald Welte }
1502e4e6a17SHarald Welte 
connbytes_mt_exit(void)151d3c5ee6dSJan Engelhardt static void __exit connbytes_mt_exit(void)
1522e4e6a17SHarald Welte {
15392f3b2b1SJan Engelhardt 	xt_unregister_match(&connbytes_mt_reg);
1542e4e6a17SHarald Welte }
1552e4e6a17SHarald Welte 
156d3c5ee6dSJan Engelhardt module_init(connbytes_mt_init);
157d3c5ee6dSJan Engelhardt module_exit(connbytes_mt_exit);
158