xref: /openbmc/linux/net/netfilter/xt_connbytes.c (revision 1977f032)
12e4e6a17SHarald Welte /* Kernel module to match connection tracking byte counter.
22e4e6a17SHarald Welte  * GPL (C) 2002 Martin Devera (devik@cdi.cz).
32e4e6a17SHarald Welte  */
42e4e6a17SHarald Welte #include <linux/module.h>
51977f032SJiri Slaby #include <linux/bitops.h>
62e4e6a17SHarald Welte #include <linux/skbuff.h>
72e4e6a17SHarald Welte #include <linux/netfilter/x_tables.h>
82e4e6a17SHarald Welte #include <linux/netfilter/xt_connbytes.h>
9587aa641SPatrick McHardy #include <net/netfilter/nf_conntrack.h>
102e4e6a17SHarald Welte 
112e4e6a17SHarald Welte #include <asm/div64.h>
122e4e6a17SHarald Welte 
132e4e6a17SHarald Welte MODULE_LICENSE("GPL");
142e4e6a17SHarald Welte MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
152e4e6a17SHarald Welte MODULE_DESCRIPTION("iptables match for matching number of pkts/bytes per connection");
162e4e6a17SHarald Welte MODULE_ALIAS("ipt_connbytes");
1773aaf935SJan Engelhardt MODULE_ALIAS("ip6t_connbytes");
182e4e6a17SHarald Welte 
191d93a9cbSJan Engelhardt static bool
202e4e6a17SHarald Welte match(const struct sk_buff *skb,
212e4e6a17SHarald Welte       const struct net_device *in,
222e4e6a17SHarald Welte       const struct net_device *out,
23c4986734SPatrick McHardy       const struct xt_match *match,
242e4e6a17SHarald Welte       const void *matchinfo,
252e4e6a17SHarald Welte       int offset,
262e4e6a17SHarald Welte       unsigned int protoff,
27cff533acSJan Engelhardt       bool *hotdrop)
282e4e6a17SHarald Welte {
292e4e6a17SHarald Welte 	const struct xt_connbytes_info *sinfo = matchinfo;
30a47362a2SJan Engelhardt 	const struct nf_conn *ct;
31587aa641SPatrick McHardy 	enum ip_conntrack_info ctinfo;
322e4e6a17SHarald Welte 	u_int64_t what = 0;	/* initialize to make gcc happy */
33fb74a841SPatrick McHardy 	u_int64_t bytes = 0;
34fb74a841SPatrick McHardy 	u_int64_t pkts = 0;
352e4e6a17SHarald Welte 	const struct ip_conntrack_counter *counters;
362e4e6a17SHarald Welte 
37587aa641SPatrick McHardy 	ct = nf_ct_get(skb, &ctinfo);
38587aa641SPatrick McHardy 	if (!ct)
391d93a9cbSJan Engelhardt 		return false;
40587aa641SPatrick McHardy 	counters = ct->counters;
412e4e6a17SHarald Welte 
422e4e6a17SHarald Welte 	switch (sinfo->what) {
432e4e6a17SHarald Welte 	case XT_CONNBYTES_PKTS:
442e4e6a17SHarald Welte 		switch (sinfo->direction) {
452e4e6a17SHarald Welte 		case XT_CONNBYTES_DIR_ORIGINAL:
462e4e6a17SHarald Welte 			what = counters[IP_CT_DIR_ORIGINAL].packets;
472e4e6a17SHarald Welte 			break;
482e4e6a17SHarald Welte 		case XT_CONNBYTES_DIR_REPLY:
492e4e6a17SHarald Welte 			what = counters[IP_CT_DIR_REPLY].packets;
502e4e6a17SHarald Welte 			break;
512e4e6a17SHarald Welte 		case XT_CONNBYTES_DIR_BOTH:
522e4e6a17SHarald Welte 			what = counters[IP_CT_DIR_ORIGINAL].packets;
532e4e6a17SHarald Welte 			what += counters[IP_CT_DIR_REPLY].packets;
542e4e6a17SHarald Welte 			break;
552e4e6a17SHarald Welte 		}
562e4e6a17SHarald Welte 		break;
572e4e6a17SHarald Welte 	case XT_CONNBYTES_BYTES:
582e4e6a17SHarald Welte 		switch (sinfo->direction) {
592e4e6a17SHarald Welte 		case XT_CONNBYTES_DIR_ORIGINAL:
602e4e6a17SHarald Welte 			what = counters[IP_CT_DIR_ORIGINAL].bytes;
612e4e6a17SHarald Welte 			break;
622e4e6a17SHarald Welte 		case XT_CONNBYTES_DIR_REPLY:
632e4e6a17SHarald Welte 			what = counters[IP_CT_DIR_REPLY].bytes;
642e4e6a17SHarald Welte 			break;
652e4e6a17SHarald Welte 		case XT_CONNBYTES_DIR_BOTH:
662e4e6a17SHarald Welte 			what = counters[IP_CT_DIR_ORIGINAL].bytes;
672e4e6a17SHarald Welte 			what += counters[IP_CT_DIR_REPLY].bytes;
682e4e6a17SHarald Welte 			break;
692e4e6a17SHarald Welte 		}
702e4e6a17SHarald Welte 		break;
712e4e6a17SHarald Welte 	case XT_CONNBYTES_AVGPKT:
722e4e6a17SHarald Welte 		switch (sinfo->direction) {
732e4e6a17SHarald Welte 		case XT_CONNBYTES_DIR_ORIGINAL:
74fb74a841SPatrick McHardy 			bytes = counters[IP_CT_DIR_ORIGINAL].bytes;
75fb74a841SPatrick McHardy 			pkts  = counters[IP_CT_DIR_ORIGINAL].packets;
762e4e6a17SHarald Welte 			break;
772e4e6a17SHarald Welte 		case XT_CONNBYTES_DIR_REPLY:
78fb74a841SPatrick McHardy 			bytes = counters[IP_CT_DIR_REPLY].bytes;
79fb74a841SPatrick McHardy 			pkts  = counters[IP_CT_DIR_REPLY].packets;
802e4e6a17SHarald Welte 			break;
812e4e6a17SHarald Welte 		case XT_CONNBYTES_DIR_BOTH:
822e4e6a17SHarald Welte 			bytes = counters[IP_CT_DIR_ORIGINAL].bytes +
832e4e6a17SHarald Welte 				counters[IP_CT_DIR_REPLY].bytes;
842e4e6a17SHarald Welte 			pkts  = counters[IP_CT_DIR_ORIGINAL].packets +
852e4e6a17SHarald Welte 				counters[IP_CT_DIR_REPLY].packets;
862e4e6a17SHarald Welte 			break;
872e4e6a17SHarald Welte 		}
88fb74a841SPatrick McHardy 		if (pkts != 0)
89fb74a841SPatrick McHardy 			what = div64_64(bytes, pkts);
902e4e6a17SHarald Welte 		break;
912e4e6a17SHarald Welte 	}
922e4e6a17SHarald Welte 
932e4e6a17SHarald Welte 	if (sinfo->count.to)
947c4e36bcSJan Engelhardt 		return what <= sinfo->count.to && what >= sinfo->count.from;
952e4e6a17SHarald Welte 	else
967c4e36bcSJan Engelhardt 		return what >= sinfo->count.from;
972e4e6a17SHarald Welte }
982e4e6a17SHarald Welte 
99ccb79bdcSJan Engelhardt static bool check(const char *tablename,
1002e4e6a17SHarald Welte 		  const void *ip,
101c4986734SPatrick McHardy 		  const struct xt_match *match,
1022e4e6a17SHarald Welte 		  void *matchinfo,
1032e4e6a17SHarald Welte 		  unsigned int hook_mask)
1042e4e6a17SHarald Welte {
1052e4e6a17SHarald Welte 	const struct xt_connbytes_info *sinfo = matchinfo;
1062e4e6a17SHarald Welte 
1072e4e6a17SHarald Welte 	if (sinfo->what != XT_CONNBYTES_PKTS &&
1082e4e6a17SHarald Welte 	    sinfo->what != XT_CONNBYTES_BYTES &&
1092e4e6a17SHarald Welte 	    sinfo->what != XT_CONNBYTES_AVGPKT)
110ccb79bdcSJan Engelhardt 		return false;
1112e4e6a17SHarald Welte 
1122e4e6a17SHarald Welte 	if (sinfo->direction != XT_CONNBYTES_DIR_ORIGINAL &&
1132e4e6a17SHarald Welte 	    sinfo->direction != XT_CONNBYTES_DIR_REPLY &&
1142e4e6a17SHarald Welte 	    sinfo->direction != XT_CONNBYTES_DIR_BOTH)
115ccb79bdcSJan Engelhardt 		return false;
1162e4e6a17SHarald Welte 
11711078c37SYasuyuki Kozakai 	if (nf_ct_l3proto_try_module_get(match->family) < 0) {
11811078c37SYasuyuki Kozakai 		printk(KERN_WARNING "can't load conntrack support for "
11911078c37SYasuyuki Kozakai 				    "proto=%d\n", match->family);
120ccb79bdcSJan Engelhardt 		return false;
12111078c37SYasuyuki Kozakai 	}
12211078c37SYasuyuki Kozakai 
123ccb79bdcSJan Engelhardt 	return true;
1242e4e6a17SHarald Welte }
1252e4e6a17SHarald Welte 
12611078c37SYasuyuki Kozakai static void
12711078c37SYasuyuki Kozakai destroy(const struct xt_match *match, void *matchinfo)
12811078c37SYasuyuki Kozakai {
12911078c37SYasuyuki Kozakai 	nf_ct_l3proto_module_put(match->family);
13011078c37SYasuyuki Kozakai }
13111078c37SYasuyuki Kozakai 
1329f15c530SPatrick McHardy static struct xt_match xt_connbytes_match[] __read_mostly = {
1334470bbc7SPatrick McHardy 	{
1342e4e6a17SHarald Welte 		.name		= "connbytes",
135a45049c5SPablo Neira Ayuso 		.family		= AF_INET,
1365d04bff0SPatrick McHardy 		.checkentry	= check,
1374470bbc7SPatrick McHardy 		.match		= match,
13811078c37SYasuyuki Kozakai 		.destroy	= destroy,
1395d04bff0SPatrick McHardy 		.matchsize	= sizeof(struct xt_connbytes_info),
1402e4e6a17SHarald Welte 		.me		= THIS_MODULE
1414470bbc7SPatrick McHardy 	},
1424470bbc7SPatrick McHardy 	{
1434470bbc7SPatrick McHardy 		.name		= "connbytes",
1444470bbc7SPatrick McHardy 		.family		= AF_INET6,
1454470bbc7SPatrick McHardy 		.checkentry	= check,
1464470bbc7SPatrick McHardy 		.match		= match,
14711078c37SYasuyuki Kozakai 		.destroy	= destroy,
1484470bbc7SPatrick McHardy 		.matchsize	= sizeof(struct xt_connbytes_info),
1494470bbc7SPatrick McHardy 		.me		= THIS_MODULE
1504470bbc7SPatrick McHardy 	},
1512e4e6a17SHarald Welte };
1522e4e6a17SHarald Welte 
15365b4b4e8SAndrew Morton static int __init xt_connbytes_init(void)
1542e4e6a17SHarald Welte {
1554470bbc7SPatrick McHardy 	return xt_register_matches(xt_connbytes_match,
1564470bbc7SPatrick McHardy 				   ARRAY_SIZE(xt_connbytes_match));
1572e4e6a17SHarald Welte }
1582e4e6a17SHarald Welte 
15965b4b4e8SAndrew Morton static void __exit xt_connbytes_fini(void)
1602e4e6a17SHarald Welte {
1614470bbc7SPatrick McHardy 	xt_unregister_matches(xt_connbytes_match,
1624470bbc7SPatrick McHardy 			      ARRAY_SIZE(xt_connbytes_match));
1632e4e6a17SHarald Welte }
1642e4e6a17SHarald Welte 
16565b4b4e8SAndrew Morton module_init(xt_connbytes_init);
16665b4b4e8SAndrew Morton module_exit(xt_connbytes_fini);
167