Blame view

net/netfilter/nfnetlink_acct.c 12.7 KB
e97150df8   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
941390279   Pablo Neira Ayuso   netfilter: add ex...
2
3
4
  /*
   * (C) 2011 Pablo Neira Ayuso <pablo@netfilter.org>
   * (C) 2011 Intra2net AG <http://www.intra2net.com>
941390279   Pablo Neira Ayuso   netfilter: add ex...
5
6
7
8
9
   */
  #include <linux/init.h>
  #include <linux/module.h>
  #include <linux/kernel.h>
  #include <linux/skbuff.h>
6523cf9a4   Andrew Morton   net/netfilter/nfn...
10
  #include <linux/atomic.h>
b54ab92b8   Reshetova, Elena   netfilter: refcou...
11
  #include <linux/refcount.h>
941390279   Pablo Neira Ayuso   netfilter: add ex...
12
13
14
15
16
17
18
  #include <linux/netlink.h>
  #include <linux/rculist.h>
  #include <linux/slab.h>
  #include <linux/types.h>
  #include <linux/errno.h>
  #include <net/netlink.h>
  #include <net/sock.h>
941390279   Pablo Neira Ayuso   netfilter: add ex...
19
20
21
22
23
24
25
26
  
  #include <linux/netfilter.h>
  #include <linux/netfilter/nfnetlink.h>
  #include <linux/netfilter/nfnetlink_acct.h>
  
  MODULE_LICENSE("GPL");
  MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>");
  MODULE_DESCRIPTION("nfacct: Extended Netfilter accounting infrastructure");
941390279   Pablo Neira Ayuso   netfilter: add ex...
27
28
29
  struct nf_acct {
  	atomic64_t		pkts;
  	atomic64_t		bytes;
683399edd   Mathieu Poirier   netfilter: nfnetl...
30
  	unsigned long		flags;
941390279   Pablo Neira Ayuso   netfilter: add ex...
31
  	struct list_head	head;
b54ab92b8   Reshetova, Elena   netfilter: refcou...
32
  	refcount_t		refcnt;
941390279   Pablo Neira Ayuso   netfilter: add ex...
33
34
  	char			name[NFACCT_NAME_MAX];
  	struct rcu_head		rcu_head;
683399edd   Mathieu Poirier   netfilter: nfnetl...
35
  	char			data[0];
941390279   Pablo Neira Ayuso   netfilter: add ex...
36
  };
f111f780a   Alexey Perevalov   netfilter: nfnetl...
37
38
39
40
  struct nfacct_filter {
  	u32 value;
  	u32 mask;
  };
683399edd   Mathieu Poirier   netfilter: nfnetl...
41
  #define NFACCT_F_QUOTA (NFACCT_F_QUOTA_PKTS | NFACCT_F_QUOTA_BYTES)
b6d046880   Alexey Perevalov   netfilter: nfnetl...
42
  #define NFACCT_OVERQUOTA_BIT	2	/* NFACCT_F_OVERQUOTA */
683399edd   Mathieu Poirier   netfilter: nfnetl...
43

7b8002a15   Pablo Neira Ayuso   netfilter: nfnetl...
44
45
  static int nfnl_acct_new(struct net *net, struct sock *nfnl,
  			 struct sk_buff *skb, const struct nlmsghdr *nlh,
04ba724b6   Pablo Neira Ayuso   netfilter: nfnetl...
46
47
  			 const struct nlattr * const tb[],
  			 struct netlink_ext_ack *extack)
941390279   Pablo Neira Ayuso   netfilter: add ex...
48
49
50
  {
  	struct nf_acct *nfacct, *matching = NULL;
  	char *acct_name;
683399edd   Mathieu Poirier   netfilter: nfnetl...
51
52
  	unsigned int size = 0;
  	u32 flags = 0;
941390279   Pablo Neira Ayuso   netfilter: add ex...
53
54
55
56
57
  
  	if (!tb[NFACCT_NAME])
  		return -EINVAL;
  
  	acct_name = nla_data(tb[NFACCT_NAME]);
deadcfc33   Pablo Neira Ayuso   netfilter: nfnetl...
58
59
  	if (strlen(acct_name) == 0)
  		return -EINVAL;
941390279   Pablo Neira Ayuso   netfilter: add ex...
60

3499abb24   Andreas Schultz   netfilter: nfacct...
61
  	list_for_each_entry(nfacct, &net->nfnl_acct_list, head) {
941390279   Pablo Neira Ayuso   netfilter: add ex...
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
  		if (strncmp(nfacct->name, acct_name, NFACCT_NAME_MAX) != 0)
  			continue;
  
                  if (nlh->nlmsg_flags & NLM_F_EXCL)
  			return -EEXIST;
  
  		matching = nfacct;
  		break;
          }
  
  	if (matching) {
  		if (nlh->nlmsg_flags & NLM_F_REPLACE) {
  			/* reset counters if you request a replacement. */
  			atomic64_set(&matching->pkts, 0);
  			atomic64_set(&matching->bytes, 0);
f9da455b9   Linus Torvalds   Merge git://git.k...
77
  			smp_mb__before_atomic();
683399edd   Mathieu Poirier   netfilter: nfnetl...
78
79
  			/* reset overquota flag if quota is enabled. */
  			if ((matching->flags & NFACCT_F_QUOTA))
b6d046880   Alexey Perevalov   netfilter: nfnetl...
80
81
  				clear_bit(NFACCT_OVERQUOTA_BIT,
  					  &matching->flags);
941390279   Pablo Neira Ayuso   netfilter: add ex...
82
83
84
85
  			return 0;
  		}
  		return -EBUSY;
  	}
683399edd   Mathieu Poirier   netfilter: nfnetl...
86
87
88
89
90
91
92
93
  	if (tb[NFACCT_FLAGS]) {
  		flags = ntohl(nla_get_be32(tb[NFACCT_FLAGS]));
  		if (flags & ~NFACCT_F_QUOTA)
  			return -EOPNOTSUPP;
  		if ((flags & NFACCT_F_QUOTA) == NFACCT_F_QUOTA)
  			return -EINVAL;
  		if (flags & NFACCT_F_OVERQUOTA)
  			return -EINVAL;
eda3fc50d   Phil Turnbull   netfilter: nfnetl...
94
95
  		if ((flags & NFACCT_F_QUOTA) && !tb[NFACCT_QUOTA])
  			return -EINVAL;
683399edd   Mathieu Poirier   netfilter: nfnetl...
96
97
98
99
100
  
  		size += sizeof(u64);
  	}
  
  	nfacct = kzalloc(sizeof(struct nf_acct) + size, GFP_KERNEL);
941390279   Pablo Neira Ayuso   netfilter: add ex...
101
102
  	if (nfacct == NULL)
  		return -ENOMEM;
683399edd   Mathieu Poirier   netfilter: nfnetl...
103
104
105
106
107
108
  	if (flags & NFACCT_F_QUOTA) {
  		u64 *quota = (u64 *)nfacct->data;
  
  		*quota = be64_to_cpu(nla_get_be64(tb[NFACCT_QUOTA]));
  		nfacct->flags = flags;
  	}
4b83a9049   Eric Dumazet   netfilter: provid...
109
  	nla_strlcpy(nfacct->name, tb[NFACCT_NAME], NFACCT_NAME_MAX);
941390279   Pablo Neira Ayuso   netfilter: add ex...
110
111
112
  
  	if (tb[NFACCT_BYTES]) {
  		atomic64_set(&nfacct->bytes,
fe31d1a86   Patrick McHardy   netfilter: sparse...
113
  			     be64_to_cpu(nla_get_be64(tb[NFACCT_BYTES])));
941390279   Pablo Neira Ayuso   netfilter: add ex...
114
115
116
  	}
  	if (tb[NFACCT_PKTS]) {
  		atomic64_set(&nfacct->pkts,
fe31d1a86   Patrick McHardy   netfilter: sparse...
117
  			     be64_to_cpu(nla_get_be64(tb[NFACCT_PKTS])));
941390279   Pablo Neira Ayuso   netfilter: add ex...
118
  	}
b54ab92b8   Reshetova, Elena   netfilter: refcou...
119
  	refcount_set(&nfacct->refcnt, 1);
3499abb24   Andreas Schultz   netfilter: nfacct...
120
  	list_add_tail_rcu(&nfacct->head, &net->nfnl_acct_list);
941390279   Pablo Neira Ayuso   netfilter: add ex...
121
122
123
124
  	return 0;
  }
  
  static int
15e473046   Eric W. Biederman   netlink: Rename p...
125
  nfnl_acct_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type,
941390279   Pablo Neira Ayuso   netfilter: add ex...
126
127
128
129
  		   int event, struct nf_acct *acct)
  {
  	struct nlmsghdr *nlh;
  	struct nfgenmsg *nfmsg;
15e473046   Eric W. Biederman   netlink: Rename p...
130
  	unsigned int flags = portid ? NLM_F_MULTI : 0;
941390279   Pablo Neira Ayuso   netfilter: add ex...
131
  	u64 pkts, bytes;
d24675cb1   Alexey Perevalov   netfilter: nfnetl...
132
  	u32 old_flags;
941390279   Pablo Neira Ayuso   netfilter: add ex...
133

dedb67c4b   Pablo Neira Ayuso   netfilter: Add nf...
134
  	event = nfnl_msg_type(NFNL_SUBSYS_ACCT, event);
15e473046   Eric W. Biederman   netlink: Rename p...
135
  	nlh = nlmsg_put(skb, portid, seq, event, sizeof(*nfmsg), flags);
941390279   Pablo Neira Ayuso   netfilter: add ex...
136
137
138
139
140
141
142
  	if (nlh == NULL)
  		goto nlmsg_failure;
  
  	nfmsg = nlmsg_data(nlh);
  	nfmsg->nfgen_family = AF_UNSPEC;
  	nfmsg->version = NFNETLINK_V0;
  	nfmsg->res_id = 0;
7c8011895   David S. Miller   nfnetlink_acct: S...
143
144
  	if (nla_put_string(skb, NFACCT_NAME, acct->name))
  		goto nla_put_failure;
941390279   Pablo Neira Ayuso   netfilter: add ex...
145

d24675cb1   Alexey Perevalov   netfilter: nfnetl...
146
  	old_flags = acct->flags;
941390279   Pablo Neira Ayuso   netfilter: add ex...
147
148
149
  	if (type == NFNL_MSG_ACCT_GET_CTRZERO) {
  		pkts = atomic64_xchg(&acct->pkts, 0);
  		bytes = atomic64_xchg(&acct->bytes, 0);
f9da455b9   Linus Torvalds   Merge git://git.k...
150
  		smp_mb__before_atomic();
683399edd   Mathieu Poirier   netfilter: nfnetl...
151
  		if (acct->flags & NFACCT_F_QUOTA)
b6d046880   Alexey Perevalov   netfilter: nfnetl...
152
  			clear_bit(NFACCT_OVERQUOTA_BIT, &acct->flags);
941390279   Pablo Neira Ayuso   netfilter: add ex...
153
154
155
156
  	} else {
  		pkts = atomic64_read(&acct->pkts);
  		bytes = atomic64_read(&acct->bytes);
  	}
b46f6ded9   Nicolas Dichtel   libnl: nla_put_be...
157
158
159
160
  	if (nla_put_be64(skb, NFACCT_PKTS, cpu_to_be64(pkts),
  			 NFACCT_PAD) ||
  	    nla_put_be64(skb, NFACCT_BYTES, cpu_to_be64(bytes),
  			 NFACCT_PAD) ||
b54ab92b8   Reshetova, Elena   netfilter: refcou...
161
  	    nla_put_be32(skb, NFACCT_USE, htonl(refcount_read(&acct->refcnt))))
7c8011895   David S. Miller   nfnetlink_acct: S...
162
  		goto nla_put_failure;
683399edd   Mathieu Poirier   netfilter: nfnetl...
163
164
  	if (acct->flags & NFACCT_F_QUOTA) {
  		u64 *quota = (u64 *)acct->data;
941390279   Pablo Neira Ayuso   netfilter: add ex...
165

d24675cb1   Alexey Perevalov   netfilter: nfnetl...
166
  		if (nla_put_be32(skb, NFACCT_FLAGS, htonl(old_flags)) ||
b46f6ded9   Nicolas Dichtel   libnl: nla_put_be...
167
168
  		    nla_put_be64(skb, NFACCT_QUOTA, cpu_to_be64(*quota),
  				 NFACCT_PAD))
683399edd   Mathieu Poirier   netfilter: nfnetl...
169
170
  			goto nla_put_failure;
  	}
941390279   Pablo Neira Ayuso   netfilter: add ex...
171
172
173
174
175
176
177
178
179
180
181
182
  	nlmsg_end(skb, nlh);
  	return skb->len;
  
  nlmsg_failure:
  nla_put_failure:
  	nlmsg_cancel(skb, nlh);
  	return -1;
  }
  
  static int
  nfnl_acct_dump(struct sk_buff *skb, struct netlink_callback *cb)
  {
3499abb24   Andreas Schultz   netfilter: nfacct...
183
  	struct net *net = sock_net(skb->sk);
941390279   Pablo Neira Ayuso   netfilter: add ex...
184
  	struct nf_acct *cur, *last;
f111f780a   Alexey Perevalov   netfilter: nfnetl...
185
  	const struct nfacct_filter *filter = cb->data;
941390279   Pablo Neira Ayuso   netfilter: add ex...
186
187
188
189
190
191
192
193
194
  
  	if (cb->args[2])
  		return 0;
  
  	last = (struct nf_acct *)cb->args[1];
  	if (cb->args[1])
  		cb->args[1] = 0;
  
  	rcu_read_lock();
3499abb24   Andreas Schultz   netfilter: nfacct...
195
  	list_for_each_entry_rcu(cur, &net->nfnl_acct_list, head) {
991a6b735   Pablo Neira Ayuso   netfilter: nfnetl...
196
197
198
  		if (last) {
  			if (cur != last)
  				continue;
941390279   Pablo Neira Ayuso   netfilter: add ex...
199

991a6b735   Pablo Neira Ayuso   netfilter: nfnetl...
200
201
  			last = NULL;
  		}
f111f780a   Alexey Perevalov   netfilter: nfnetl...
202
203
204
  
  		if (filter && (cur->flags & filter->mask) != filter->value)
  			continue;
15e473046   Eric W. Biederman   netlink: Rename p...
205
  		if (nfnl_acct_fill_info(skb, NETLINK_CB(cb->skb).portid,
941390279   Pablo Neira Ayuso   netfilter: add ex...
206
207
208
209
210
211
212
213
214
215
216
217
  				       cb->nlh->nlmsg_seq,
  				       NFNL_MSG_TYPE(cb->nlh->nlmsg_type),
  				       NFNL_MSG_ACCT_NEW, cur) < 0) {
  			cb->args[1] = (unsigned long)cur;
  			break;
  		}
  	}
  	if (!cb->args[1])
  		cb->args[2] = 1;
  	rcu_read_unlock();
  	return skb->len;
  }
f111f780a   Alexey Perevalov   netfilter: nfnetl...
218
219
220
221
222
223
224
225
226
227
  static int nfnl_acct_done(struct netlink_callback *cb)
  {
  	kfree(cb->data);
  	return 0;
  }
  
  static const struct nla_policy filter_policy[NFACCT_FILTER_MAX + 1] = {
  	[NFACCT_FILTER_MASK]	= { .type = NLA_U32 },
  	[NFACCT_FILTER_VALUE]	= { .type = NLA_U32 },
  };
3e673b23b   Florian Westphal   netfilter: fix me...
228
  static int nfnl_acct_start(struct netlink_callback *cb)
f111f780a   Alexey Perevalov   netfilter: nfnetl...
229
  {
3e673b23b   Florian Westphal   netfilter: fix me...
230
  	const struct nlattr *const attr = cb->data;
f111f780a   Alexey Perevalov   netfilter: nfnetl...
231
  	struct nlattr *tb[NFACCT_FILTER_MAX + 1];
3e673b23b   Florian Westphal   netfilter: fix me...
232
  	struct nfacct_filter *filter;
f111f780a   Alexey Perevalov   netfilter: nfnetl...
233
  	int err;
3e673b23b   Florian Westphal   netfilter: fix me...
234
235
  	if (!attr)
  		return 0;
8cb081746   Johannes Berg   netlink: make val...
236
237
  	err = nla_parse_nested_deprecated(tb, NFACCT_FILTER_MAX, attr,
  					  filter_policy, NULL);
f111f780a   Alexey Perevalov   netfilter: nfnetl...
238
  	if (err < 0)
3e673b23b   Florian Westphal   netfilter: fix me...
239
  		return err;
f111f780a   Alexey Perevalov   netfilter: nfnetl...
240

017b1b6d2   Phil Turnbull   netfilter: nfnetl...
241
  	if (!tb[NFACCT_FILTER_MASK] || !tb[NFACCT_FILTER_VALUE])
3e673b23b   Florian Westphal   netfilter: fix me...
242
  		return -EINVAL;
017b1b6d2   Phil Turnbull   netfilter: nfnetl...
243

f111f780a   Alexey Perevalov   netfilter: nfnetl...
244
245
  	filter = kzalloc(sizeof(struct nfacct_filter), GFP_KERNEL);
  	if (!filter)
3e673b23b   Florian Westphal   netfilter: fix me...
246
  		return -ENOMEM;
f111f780a   Alexey Perevalov   netfilter: nfnetl...
247
248
249
  
  	filter->mask = ntohl(nla_get_be32(tb[NFACCT_FILTER_MASK]));
  	filter->value = ntohl(nla_get_be32(tb[NFACCT_FILTER_VALUE]));
3e673b23b   Florian Westphal   netfilter: fix me...
250
  	cb->data = filter;
f111f780a   Alexey Perevalov   netfilter: nfnetl...
251

3e673b23b   Florian Westphal   netfilter: fix me...
252
  	return 0;
f111f780a   Alexey Perevalov   netfilter: nfnetl...
253
  }
7b8002a15   Pablo Neira Ayuso   netfilter: nfnetl...
254
255
  static int nfnl_acct_get(struct net *net, struct sock *nfnl,
  			 struct sk_buff *skb, const struct nlmsghdr *nlh,
04ba724b6   Pablo Neira Ayuso   netfilter: nfnetl...
256
257
  			 const struct nlattr * const tb[],
  			 struct netlink_ext_ack *extack)
941390279   Pablo Neira Ayuso   netfilter: add ex...
258
  {
3ab0b245a   Pablo Neira Ayuso   netfilter: nfnetl...
259
  	int ret = -ENOENT;
941390279   Pablo Neira Ayuso   netfilter: add ex...
260
261
262
263
  	struct nf_acct *cur;
  	char *acct_name;
  
  	if (nlh->nlmsg_flags & NLM_F_DUMP) {
80d326fab   Pablo Neira Ayuso   netlink: add netl...
264
265
  		struct netlink_dump_control c = {
  			.dump = nfnl_acct_dump,
3e673b23b   Florian Westphal   netfilter: fix me...
266
  			.start = nfnl_acct_start,
f111f780a   Alexey Perevalov   netfilter: nfnetl...
267
  			.done = nfnl_acct_done,
3e673b23b   Florian Westphal   netfilter: fix me...
268
  			.data = (void *)tb[NFACCT_FILTER],
80d326fab   Pablo Neira Ayuso   netlink: add netl...
269
  		};
f111f780a   Alexey Perevalov   netfilter: nfnetl...
270

80d326fab   Pablo Neira Ayuso   netlink: add netl...
271
  		return netlink_dump_start(nfnl, skb, nlh, &c);
941390279   Pablo Neira Ayuso   netfilter: add ex...
272
273
274
275
276
  	}
  
  	if (!tb[NFACCT_NAME])
  		return -EINVAL;
  	acct_name = nla_data(tb[NFACCT_NAME]);
3499abb24   Andreas Schultz   netfilter: nfacct...
277
  	list_for_each_entry(cur, &net->nfnl_acct_list, head) {
941390279   Pablo Neira Ayuso   netfilter: add ex...
278
279
280
281
282
283
  		struct sk_buff *skb2;
  
  		if (strncmp(cur->name, acct_name, NFACCT_NAME_MAX)!= 0)
  			continue;
  
  		skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3ab0b245a   Pablo Neira Ayuso   netfilter: nfnetl...
284
285
  		if (skb2 == NULL) {
  			ret = -ENOMEM;
941390279   Pablo Neira Ayuso   netfilter: add ex...
286
  			break;
3ab0b245a   Pablo Neira Ayuso   netfilter: nfnetl...
287
  		}
941390279   Pablo Neira Ayuso   netfilter: add ex...
288

15e473046   Eric W. Biederman   netlink: Rename p...
289
  		ret = nfnl_acct_fill_info(skb2, NETLINK_CB(skb).portid,
941390279   Pablo Neira Ayuso   netfilter: add ex...
290
291
292
  					 nlh->nlmsg_seq,
  					 NFNL_MSG_TYPE(nlh->nlmsg_type),
  					 NFNL_MSG_ACCT_NEW, cur);
3ab0b245a   Pablo Neira Ayuso   netfilter: nfnetl...
293
  		if (ret <= 0) {
941390279   Pablo Neira Ayuso   netfilter: add ex...
294
  			kfree_skb(skb2);
3ab0b245a   Pablo Neira Ayuso   netfilter: nfnetl...
295
296
  			break;
  		}
15e473046   Eric W. Biederman   netlink: Rename p...
297
  		ret = netlink_unicast(nfnl, skb2, NETLINK_CB(skb).portid,
3ab0b245a   Pablo Neira Ayuso   netfilter: nfnetl...
298
299
300
  					MSG_DONTWAIT);
  		if (ret > 0)
  			ret = 0;
941390279   Pablo Neira Ayuso   netfilter: add ex...
301

3ab0b245a   Pablo Neira Ayuso   netfilter: nfnetl...
302
303
  		/* this avoids a loop in nfnetlink. */
  		return ret == -EAGAIN ? -ENOBUFS : ret;
941390279   Pablo Neira Ayuso   netfilter: add ex...
304
305
306
307
308
309
310
311
  	}
  	return ret;
  }
  
  /* try to delete object, fail if it is still in use. */
  static int nfnl_acct_try_del(struct nf_acct *cur)
  {
  	int ret = 0;
12be15dd5   Liping Zhang   netfilter: nfnetl...
312
313
314
  	/* We want to avoid races with nfnl_acct_put. So only when the current
  	 * refcnt is 1, we decrease it to 0.
  	 */
b54ab92b8   Reshetova, Elena   netfilter: refcou...
315
  	if (refcount_dec_if_one(&cur->refcnt)) {
941390279   Pablo Neira Ayuso   netfilter: add ex...
316
317
318
319
  		/* We are protected by nfnl mutex. */
  		list_del_rcu(&cur->head);
  		kfree_rcu(cur, rcu_head);
  	} else {
941390279   Pablo Neira Ayuso   netfilter: add ex...
320
321
322
323
  		ret = -EBUSY;
  	}
  	return ret;
  }
7b8002a15   Pablo Neira Ayuso   netfilter: nfnetl...
324
325
  static int nfnl_acct_del(struct net *net, struct sock *nfnl,
  			 struct sk_buff *skb, const struct nlmsghdr *nlh,
04ba724b6   Pablo Neira Ayuso   netfilter: nfnetl...
326
327
  			 const struct nlattr * const tb[],
  			 struct netlink_ext_ack *extack)
941390279   Pablo Neira Ayuso   netfilter: add ex...
328
  {
93fac10b9   Liping Zhang   netfilter: nfnetl...
329
  	struct nf_acct *cur, *tmp;
941390279   Pablo Neira Ayuso   netfilter: add ex...
330
  	int ret = -ENOENT;
93fac10b9   Liping Zhang   netfilter: nfnetl...
331
  	char *acct_name;
941390279   Pablo Neira Ayuso   netfilter: add ex...
332
333
  
  	if (!tb[NFACCT_NAME]) {
93fac10b9   Liping Zhang   netfilter: nfnetl...
334
  		list_for_each_entry_safe(cur, tmp, &net->nfnl_acct_list, head)
941390279   Pablo Neira Ayuso   netfilter: add ex...
335
336
337
338
339
  			nfnl_acct_try_del(cur);
  
  		return 0;
  	}
  	acct_name = nla_data(tb[NFACCT_NAME]);
3499abb24   Andreas Schultz   netfilter: nfacct...
340
  	list_for_each_entry(cur, &net->nfnl_acct_list, head) {
941390279   Pablo Neira Ayuso   netfilter: add ex...
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
  		if (strncmp(cur->name, acct_name, NFACCT_NAME_MAX) != 0)
  			continue;
  
  		ret = nfnl_acct_try_del(cur);
  		if (ret < 0)
  			return ret;
  
  		break;
  	}
  	return ret;
  }
  
  static const struct nla_policy nfnl_acct_policy[NFACCT_MAX+1] = {
  	[NFACCT_NAME] = { .type = NLA_NUL_STRING, .len = NFACCT_NAME_MAX-1 },
  	[NFACCT_BYTES] = { .type = NLA_U64 },
  	[NFACCT_PKTS] = { .type = NLA_U64 },
683399edd   Mathieu Poirier   netfilter: nfnetl...
357
358
  	[NFACCT_FLAGS] = { .type = NLA_U32 },
  	[NFACCT_QUOTA] = { .type = NLA_U64 },
f111f780a   Alexey Perevalov   netfilter: nfnetl...
359
  	[NFACCT_FILTER] = {.type = NLA_NESTED },
941390279   Pablo Neira Ayuso   netfilter: add ex...
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
  };
  
  static const struct nfnl_callback nfnl_acct_cb[NFNL_MSG_ACCT_MAX] = {
  	[NFNL_MSG_ACCT_NEW]		= { .call = nfnl_acct_new,
  					    .attr_count = NFACCT_MAX,
  					    .policy = nfnl_acct_policy },
  	[NFNL_MSG_ACCT_GET] 		= { .call = nfnl_acct_get,
  					    .attr_count = NFACCT_MAX,
  					    .policy = nfnl_acct_policy },
  	[NFNL_MSG_ACCT_GET_CTRZERO] 	= { .call = nfnl_acct_get,
  					    .attr_count = NFACCT_MAX,
  					    .policy = nfnl_acct_policy },
  	[NFNL_MSG_ACCT_DEL]		= { .call = nfnl_acct_del,
  					    .attr_count = NFACCT_MAX,
  					    .policy = nfnl_acct_policy },
  };
  
  static const struct nfnetlink_subsystem nfnl_acct_subsys = {
  	.name				= "acct",
  	.subsys_id			= NFNL_SUBSYS_ACCT,
  	.cb_count			= NFNL_MSG_ACCT_MAX,
  	.cb				= nfnl_acct_cb,
  };
  
  MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_ACCT);
3499abb24   Andreas Schultz   netfilter: nfacct...
385
  struct nf_acct *nfnl_acct_find_get(struct net *net, const char *acct_name)
941390279   Pablo Neira Ayuso   netfilter: add ex...
386
387
388
389
  {
  	struct nf_acct *cur, *acct = NULL;
  
  	rcu_read_lock();
3499abb24   Andreas Schultz   netfilter: nfacct...
390
  	list_for_each_entry_rcu(cur, &net->nfnl_acct_list, head) {
941390279   Pablo Neira Ayuso   netfilter: add ex...
391
392
393
394
395
  		if (strncmp(cur->name, acct_name, NFACCT_NAME_MAX)!= 0)
  			continue;
  
  		if (!try_module_get(THIS_MODULE))
  			goto err;
b54ab92b8   Reshetova, Elena   netfilter: refcou...
396
  		if (!refcount_inc_not_zero(&cur->refcnt)) {
941390279   Pablo Neira Ayuso   netfilter: add ex...
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
  			module_put(THIS_MODULE);
  			goto err;
  		}
  
  		acct = cur;
  		break;
  	}
  err:
  	rcu_read_unlock();
  	return acct;
  }
  EXPORT_SYMBOL_GPL(nfnl_acct_find_get);
  
  void nfnl_acct_put(struct nf_acct *acct)
  {
b54ab92b8   Reshetova, Elena   netfilter: refcou...
412
  	if (refcount_dec_and_test(&acct->refcnt))
3499abb24   Andreas Schultz   netfilter: nfacct...
413
  		kfree_rcu(acct, rcu_head);
941390279   Pablo Neira Ayuso   netfilter: add ex...
414
415
416
417
418
419
420
421
422
423
  	module_put(THIS_MODULE);
  }
  EXPORT_SYMBOL_GPL(nfnl_acct_put);
  
  void nfnl_acct_update(const struct sk_buff *skb, struct nf_acct *nfacct)
  {
  	atomic64_inc(&nfacct->pkts);
  	atomic64_add(skb->len, &nfacct->bytes);
  }
  EXPORT_SYMBOL_GPL(nfnl_acct_update);
aca300183   Liping Zhang   netfilter: nfnetl...
424
  static void nfnl_overquota_report(struct net *net, struct nf_acct *nfacct)
683399edd   Mathieu Poirier   netfilter: nfnetl...
425
426
427
428
429
430
431
432
433
434
435
436
437
438
  {
  	int ret;
  	struct sk_buff *skb;
  
  	skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
  	if (skb == NULL)
  		return;
  
  	ret = nfnl_acct_fill_info(skb, 0, 0, NFNL_MSG_ACCT_OVERQUOTA, 0,
  				  nfacct);
  	if (ret <= 0) {
  		kfree_skb(skb);
  		return;
  	}
aca300183   Liping Zhang   netfilter: nfnetl...
439
  	netlink_broadcast(net->nfnl, skb, 0, NFNLGRP_ACCT_QUOTA,
683399edd   Mathieu Poirier   netfilter: nfnetl...
440
441
  			  GFP_ATOMIC);
  }
cceae76ef   Taehee Yoo   netfilter: nfnetl...
442
  int nfnl_acct_overquota(struct net *net, struct nf_acct *nfacct)
683399edd   Mathieu Poirier   netfilter: nfnetl...
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
  {
  	u64 now;
  	u64 *quota;
  	int ret = NFACCT_UNDERQUOTA;
  
  	/* no place here if we don't have a quota */
  	if (!(nfacct->flags & NFACCT_F_QUOTA))
  		return NFACCT_NO_QUOTA;
  
  	quota = (u64 *)nfacct->data;
  	now = (nfacct->flags & NFACCT_F_QUOTA_PKTS) ?
  	       atomic64_read(&nfacct->pkts) : atomic64_read(&nfacct->bytes);
  
  	ret = now > *quota;
  
  	if (now >= *quota &&
b6d046880   Alexey Perevalov   netfilter: nfnetl...
459
  	    !test_and_set_bit(NFACCT_OVERQUOTA_BIT, &nfacct->flags)) {
aca300183   Liping Zhang   netfilter: nfnetl...
460
  		nfnl_overquota_report(net, nfacct);
683399edd   Mathieu Poirier   netfilter: nfnetl...
461
462
463
464
465
  	}
  
  	return ret;
  }
  EXPORT_SYMBOL_GPL(nfnl_acct_overquota);
3499abb24   Andreas Schultz   netfilter: nfacct...
466
467
468
469
470
471
472
473
474
475
476
477
478
  static int __net_init nfnl_acct_net_init(struct net *net)
  {
  	INIT_LIST_HEAD(&net->nfnl_acct_list);
  
  	return 0;
  }
  
  static void __net_exit nfnl_acct_net_exit(struct net *net)
  {
  	struct nf_acct *cur, *tmp;
  
  	list_for_each_entry_safe(cur, tmp, &net->nfnl_acct_list, head) {
  		list_del_rcu(&cur->head);
b54ab92b8   Reshetova, Elena   netfilter: refcou...
479
  		if (refcount_dec_and_test(&cur->refcnt))
3499abb24   Andreas Schultz   netfilter: nfacct...
480
481
482
483
484
485
486
487
  			kfree_rcu(cur, rcu_head);
  	}
  }
  
  static struct pernet_operations nfnl_acct_ops = {
          .init   = nfnl_acct_net_init,
          .exit   = nfnl_acct_net_exit,
  };
941390279   Pablo Neira Ayuso   netfilter: add ex...
488
489
490
  static int __init nfnl_acct_init(void)
  {
  	int ret;
3499abb24   Andreas Schultz   netfilter: nfacct...
491
492
493
494
495
496
  	ret = register_pernet_subsys(&nfnl_acct_ops);
  	if (ret < 0) {
  		pr_err("nfnl_acct_init: failed to register pernet ops
  ");
  		goto err_out;
  	}
941390279   Pablo Neira Ayuso   netfilter: add ex...
497
498
499
500
  	ret = nfnetlink_subsys_register(&nfnl_acct_subsys);
  	if (ret < 0) {
  		pr_err("nfnl_acct_init: cannot register with nfnetlink.
  ");
3499abb24   Andreas Schultz   netfilter: nfacct...
501
  		goto cleanup_pernet;
941390279   Pablo Neira Ayuso   netfilter: add ex...
502
503
  	}
  	return 0;
3499abb24   Andreas Schultz   netfilter: nfacct...
504
505
506
  
  cleanup_pernet:
  	unregister_pernet_subsys(&nfnl_acct_ops);
941390279   Pablo Neira Ayuso   netfilter: add ex...
507
508
509
510
511
512
  err_out:
  	return ret;
  }
  
  static void __exit nfnl_acct_exit(void)
  {
941390279   Pablo Neira Ayuso   netfilter: add ex...
513
  	nfnetlink_subsys_unregister(&nfnl_acct_subsys);
3499abb24   Andreas Schultz   netfilter: nfacct...
514
  	unregister_pernet_subsys(&nfnl_acct_ops);
941390279   Pablo Neira Ayuso   netfilter: add ex...
515
516
517
518
  }
  
  module_init(nfnl_acct_init);
  module_exit(nfnl_acct_exit);