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