Linux Audio

Check our new training course

Loading...
v5.14.15
  1/* Kernel module to match connection tracking byte counter.
  2 * GPL (C) 2002 Martin Devera (devik@cdi.cz).
  3 */
  4#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  5#include <linux/module.h>
  6#include <linux/bitops.h>
  7#include <linux/skbuff.h>
  8#include <linux/math64.h>
  9#include <linux/netfilter/x_tables.h>
 10#include <linux/netfilter/xt_connbytes.h>
 11#include <net/netfilter/nf_conntrack.h>
 12#include <net/netfilter/nf_conntrack_acct.h>
 13
 14MODULE_LICENSE("GPL");
 15MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
 16MODULE_DESCRIPTION("Xtables: Number of packets/bytes per connection matching");
 17MODULE_ALIAS("ipt_connbytes");
 18MODULE_ALIAS("ip6t_connbytes");
 19
 20static bool
 21connbytes_mt(const struct sk_buff *skb, struct xt_action_param *par)
 22{
 23	const struct xt_connbytes_info *sinfo = par->matchinfo;
 24	const struct nf_conn *ct;
 25	enum ip_conntrack_info ctinfo;
 26	u_int64_t what = 0;	/* initialize to make gcc happy */
 27	u_int64_t bytes = 0;
 28	u_int64_t pkts = 0;
 29	const struct nf_conn_acct *acct;
 30	const struct nf_conn_counter *counters;
 31
 32	ct = nf_ct_get(skb, &ctinfo);
 33	if (!ct)
 34		return false;
 35
 36	acct = nf_conn_acct_find(ct);
 37	if (!acct)
 38		return false;
 39
 40	counters = acct->counter;
 41	switch (sinfo->what) {
 42	case XT_CONNBYTES_PKTS:
 43		switch (sinfo->direction) {
 44		case XT_CONNBYTES_DIR_ORIGINAL:
 45			what = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].packets);
 46			break;
 47		case XT_CONNBYTES_DIR_REPLY:
 48			what = atomic64_read(&counters[IP_CT_DIR_REPLY].packets);
 49			break;
 50		case XT_CONNBYTES_DIR_BOTH:
 51			what = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].packets);
 52			what += atomic64_read(&counters[IP_CT_DIR_REPLY].packets);
 53			break;
 54		}
 55		break;
 56	case XT_CONNBYTES_BYTES:
 57		switch (sinfo->direction) {
 58		case XT_CONNBYTES_DIR_ORIGINAL:
 59			what = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].bytes);
 60			break;
 61		case XT_CONNBYTES_DIR_REPLY:
 62			what = atomic64_read(&counters[IP_CT_DIR_REPLY].bytes);
 63			break;
 64		case XT_CONNBYTES_DIR_BOTH:
 65			what = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].bytes);
 66			what += atomic64_read(&counters[IP_CT_DIR_REPLY].bytes);
 67			break;
 68		}
 69		break;
 70	case XT_CONNBYTES_AVGPKT:
 71		switch (sinfo->direction) {
 72		case XT_CONNBYTES_DIR_ORIGINAL:
 73			bytes = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].bytes);
 74			pkts  = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].packets);
 75			break;
 76		case XT_CONNBYTES_DIR_REPLY:
 77			bytes = atomic64_read(&counters[IP_CT_DIR_REPLY].bytes);
 78			pkts  = atomic64_read(&counters[IP_CT_DIR_REPLY].packets);
 79			break;
 80		case XT_CONNBYTES_DIR_BOTH:
 81			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);
 85			break;
 86		}
 87		if (pkts != 0)
 88			what = div64_u64(bytes, pkts);
 89		break;
 90	}
 91
 92	if (sinfo->count.to >= sinfo->count.from)
 93		return what <= sinfo->count.to && what >= sinfo->count.from;
 94	else /* inverted */
 95		return what < sinfo->count.to || what > sinfo->count.from;
 96}
 97
 98static int connbytes_mt_check(const struct xt_mtchk_param *par)
 99{
100	const struct xt_connbytes_info *sinfo = par->matchinfo;
101	int ret;
102
103	if (sinfo->what != XT_CONNBYTES_PKTS &&
104	    sinfo->what != XT_CONNBYTES_BYTES &&
105	    sinfo->what != XT_CONNBYTES_AVGPKT)
106		return -EINVAL;
107
108	if (sinfo->direction != XT_CONNBYTES_DIR_ORIGINAL &&
109	    sinfo->direction != XT_CONNBYTES_DIR_REPLY &&
110	    sinfo->direction != XT_CONNBYTES_DIR_BOTH)
111		return -EINVAL;
112
113	ret = nf_ct_netns_get(par->net, par->family);
114	if (ret < 0)
115		pr_info_ratelimited("cannot load conntrack support for proto=%u\n",
116				    par->family);
117
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)) {
123		pr_warn("Forcing CT accounting to be enabled\n");
124		nf_ct_set_acct(par->net, true);
125	}
126
127	return ret;
128}
129
130static void connbytes_mt_destroy(const struct xt_mtdtor_param *par)
131{
132	nf_ct_netns_put(par->net, par->family);
133}
134
135static 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,
144};
145
146static int __init connbytes_mt_init(void)
147{
148	return xt_register_match(&connbytes_mt_reg);
149}
150
151static void __exit connbytes_mt_exit(void)
152{
153	xt_unregister_match(&connbytes_mt_reg);
154}
155
156module_init(connbytes_mt_init);
157module_exit(connbytes_mt_exit);
v3.1
  1/* Kernel module to match connection tracking byte counter.
  2 * GPL (C) 2002 Martin Devera (devik@cdi.cz).
  3 */
  4#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  5#include <linux/module.h>
  6#include <linux/bitops.h>
  7#include <linux/skbuff.h>
  8#include <linux/math64.h>
  9#include <linux/netfilter/x_tables.h>
 10#include <linux/netfilter/xt_connbytes.h>
 11#include <net/netfilter/nf_conntrack.h>
 12#include <net/netfilter/nf_conntrack_acct.h>
 13
 14MODULE_LICENSE("GPL");
 15MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
 16MODULE_DESCRIPTION("Xtables: Number of packets/bytes per connection matching");
 17MODULE_ALIAS("ipt_connbytes");
 18MODULE_ALIAS("ip6t_connbytes");
 19
 20static bool
 21connbytes_mt(const struct sk_buff *skb, struct xt_action_param *par)
 22{
 23	const struct xt_connbytes_info *sinfo = par->matchinfo;
 24	const struct nf_conn *ct;
 25	enum ip_conntrack_info ctinfo;
 26	u_int64_t what = 0;	/* initialize to make gcc happy */
 27	u_int64_t bytes = 0;
 28	u_int64_t pkts = 0;
 
 29	const struct nf_conn_counter *counters;
 30
 31	ct = nf_ct_get(skb, &ctinfo);
 32	if (!ct)
 33		return false;
 34
 35	counters = nf_conn_acct_find(ct);
 36	if (!counters)
 37		return false;
 38
 
 39	switch (sinfo->what) {
 40	case XT_CONNBYTES_PKTS:
 41		switch (sinfo->direction) {
 42		case XT_CONNBYTES_DIR_ORIGINAL:
 43			what = counters[IP_CT_DIR_ORIGINAL].packets;
 44			break;
 45		case XT_CONNBYTES_DIR_REPLY:
 46			what = counters[IP_CT_DIR_REPLY].packets;
 47			break;
 48		case XT_CONNBYTES_DIR_BOTH:
 49			what = counters[IP_CT_DIR_ORIGINAL].packets;
 50			what += counters[IP_CT_DIR_REPLY].packets;
 51			break;
 52		}
 53		break;
 54	case XT_CONNBYTES_BYTES:
 55		switch (sinfo->direction) {
 56		case XT_CONNBYTES_DIR_ORIGINAL:
 57			what = counters[IP_CT_DIR_ORIGINAL].bytes;
 58			break;
 59		case XT_CONNBYTES_DIR_REPLY:
 60			what = counters[IP_CT_DIR_REPLY].bytes;
 61			break;
 62		case XT_CONNBYTES_DIR_BOTH:
 63			what = counters[IP_CT_DIR_ORIGINAL].bytes;
 64			what += counters[IP_CT_DIR_REPLY].bytes;
 65			break;
 66		}
 67		break;
 68	case XT_CONNBYTES_AVGPKT:
 69		switch (sinfo->direction) {
 70		case XT_CONNBYTES_DIR_ORIGINAL:
 71			bytes = counters[IP_CT_DIR_ORIGINAL].bytes;
 72			pkts  = counters[IP_CT_DIR_ORIGINAL].packets;
 73			break;
 74		case XT_CONNBYTES_DIR_REPLY:
 75			bytes = counters[IP_CT_DIR_REPLY].bytes;
 76			pkts  = counters[IP_CT_DIR_REPLY].packets;
 77			break;
 78		case XT_CONNBYTES_DIR_BOTH:
 79			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;
 83			break;
 84		}
 85		if (pkts != 0)
 86			what = div64_u64(bytes, pkts);
 87		break;
 88	}
 89
 90	if (sinfo->count.to)
 91		return what <= sinfo->count.to && what >= sinfo->count.from;
 92	else
 93		return what >= sinfo->count.from;
 94}
 95
 96static int connbytes_mt_check(const struct xt_mtchk_param *par)
 97{
 98	const struct xt_connbytes_info *sinfo = par->matchinfo;
 99	int ret;
100
101	if (sinfo->what != XT_CONNBYTES_PKTS &&
102	    sinfo->what != XT_CONNBYTES_BYTES &&
103	    sinfo->what != XT_CONNBYTES_AVGPKT)
104		return -EINVAL;
105
106	if (sinfo->direction != XT_CONNBYTES_DIR_ORIGINAL &&
107	    sinfo->direction != XT_CONNBYTES_DIR_REPLY &&
108	    sinfo->direction != XT_CONNBYTES_DIR_BOTH)
109		return -EINVAL;
110
111	ret = nf_ct_l3proto_try_module_get(par->family);
112	if (ret < 0)
113		pr_info("cannot load conntrack support for proto=%u\n",
114			par->family);
115
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
125	return ret;
126}
127
128static void connbytes_mt_destroy(const struct xt_mtdtor_param *par)
129{
130	nf_ct_l3proto_module_put(par->family);
131}
132
133static 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,
142};
143
144static int __init connbytes_mt_init(void)
145{
146	return xt_register_match(&connbytes_mt_reg);
147}
148
149static void __exit connbytes_mt_exit(void)
150{
151	xt_unregister_match(&connbytes_mt_reg);
152}
153
154module_init(connbytes_mt_init);
155module_exit(connbytes_mt_exit);