]> git.karo-electronics.de Git - karo-tx-linux.git/blob - net/netfilter/nfnetlink_acct.c
arm: imx: tx6: mfgtool defconfig
[karo-tx-linux.git] / net / netfilter / nfnetlink_acct.c
1 /*
2  * (C) 2011 Pablo Neira Ayuso <pablo@netfilter.org>
3  * (C) 2011 Intra2net AG <http://www.intra2net.com>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation (or any later at your option).
8  */
9 #include <linux/init.h>
10 #include <linux/module.h>
11 #include <linux/kernel.h>
12 #include <linux/skbuff.h>
13 #include <linux/atomic.h>
14 #include <linux/netlink.h>
15 #include <linux/rculist.h>
16 #include <linux/slab.h>
17 #include <linux/types.h>
18 #include <linux/errno.h>
19 #include <net/netlink.h>
20 #include <net/sock.h>
21
22 #include <linux/netfilter.h>
23 #include <linux/netfilter/nfnetlink.h>
24 #include <linux/netfilter/nfnetlink_acct.h>
25
26 MODULE_LICENSE("GPL");
27 MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>");
28 MODULE_DESCRIPTION("nfacct: Extended Netfilter accounting infrastructure");
29
30 static LIST_HEAD(nfnl_acct_list);
31
32 struct nf_acct {
33         atomic64_t              pkts;
34         atomic64_t              bytes;
35         unsigned long           flags;
36         struct list_head        head;
37         atomic_t                refcnt;
38         char                    name[NFACCT_NAME_MAX];
39         struct rcu_head         rcu_head;
40         char                    data[0];
41 };
42
43 #define NFACCT_F_QUOTA (NFACCT_F_QUOTA_PKTS | NFACCT_F_QUOTA_BYTES)
44
45 static int
46 nfnl_acct_new(struct sock *nfnl, struct sk_buff *skb,
47              const struct nlmsghdr *nlh, const struct nlattr * const tb[])
48 {
49         struct nf_acct *nfacct, *matching = NULL;
50         char *acct_name;
51         unsigned int size = 0;
52         u32 flags = 0;
53
54         if (!tb[NFACCT_NAME])
55                 return -EINVAL;
56
57         acct_name = nla_data(tb[NFACCT_NAME]);
58         if (strlen(acct_name) == 0)
59                 return -EINVAL;
60
61         list_for_each_entry(nfacct, &nfnl_acct_list, head) {
62                 if (strncmp(nfacct->name, acct_name, NFACCT_NAME_MAX) != 0)
63                         continue;
64
65                 if (nlh->nlmsg_flags & NLM_F_EXCL)
66                         return -EEXIST;
67
68                 matching = nfacct;
69                 break;
70         }
71
72         if (matching) {
73                 if (nlh->nlmsg_flags & NLM_F_REPLACE) {
74                         /* reset counters if you request a replacement. */
75                         atomic64_set(&matching->pkts, 0);
76                         atomic64_set(&matching->bytes, 0);
77                         smp_mb__before_atomic();
78                         /* reset overquota flag if quota is enabled. */
79                         if ((matching->flags & NFACCT_F_QUOTA))
80                                 clear_bit(NFACCT_F_OVERQUOTA, &matching->flags);
81                         return 0;
82                 }
83                 return -EBUSY;
84         }
85
86         if (tb[NFACCT_FLAGS]) {
87                 flags = ntohl(nla_get_be32(tb[NFACCT_FLAGS]));
88                 if (flags & ~NFACCT_F_QUOTA)
89                         return -EOPNOTSUPP;
90                 if ((flags & NFACCT_F_QUOTA) == NFACCT_F_QUOTA)
91                         return -EINVAL;
92                 if (flags & NFACCT_F_OVERQUOTA)
93                         return -EINVAL;
94
95                 size += sizeof(u64);
96         }
97
98         nfacct = kzalloc(sizeof(struct nf_acct) + size, GFP_KERNEL);
99         if (nfacct == NULL)
100                 return -ENOMEM;
101
102         if (flags & NFACCT_F_QUOTA) {
103                 u64 *quota = (u64 *)nfacct->data;
104
105                 *quota = be64_to_cpu(nla_get_be64(tb[NFACCT_QUOTA]));
106                 nfacct->flags = flags;
107         }
108
109         strncpy(nfacct->name, nla_data(tb[NFACCT_NAME]), NFACCT_NAME_MAX);
110
111         if (tb[NFACCT_BYTES]) {
112                 atomic64_set(&nfacct->bytes,
113                              be64_to_cpu(nla_get_be64(tb[NFACCT_BYTES])));
114         }
115         if (tb[NFACCT_PKTS]) {
116                 atomic64_set(&nfacct->pkts,
117                              be64_to_cpu(nla_get_be64(tb[NFACCT_PKTS])));
118         }
119         atomic_set(&nfacct->refcnt, 1);
120         list_add_tail_rcu(&nfacct->head, &nfnl_acct_list);
121         return 0;
122 }
123
124 static int
125 nfnl_acct_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type,
126                    int event, struct nf_acct *acct)
127 {
128         struct nlmsghdr *nlh;
129         struct nfgenmsg *nfmsg;
130         unsigned int flags = portid ? NLM_F_MULTI : 0;
131         u64 pkts, bytes;
132
133         event |= NFNL_SUBSYS_ACCT << 8;
134         nlh = nlmsg_put(skb, portid, seq, event, sizeof(*nfmsg), flags);
135         if (nlh == NULL)
136                 goto nlmsg_failure;
137
138         nfmsg = nlmsg_data(nlh);
139         nfmsg->nfgen_family = AF_UNSPEC;
140         nfmsg->version = NFNETLINK_V0;
141         nfmsg->res_id = 0;
142
143         if (nla_put_string(skb, NFACCT_NAME, acct->name))
144                 goto nla_put_failure;
145
146         if (type == NFNL_MSG_ACCT_GET_CTRZERO) {
147                 pkts = atomic64_xchg(&acct->pkts, 0);
148                 bytes = atomic64_xchg(&acct->bytes, 0);
149                 smp_mb__before_atomic();
150                 if (acct->flags & NFACCT_F_QUOTA)
151                         clear_bit(NFACCT_F_OVERQUOTA, &acct->flags);
152         } else {
153                 pkts = atomic64_read(&acct->pkts);
154                 bytes = atomic64_read(&acct->bytes);
155         }
156         if (nla_put_be64(skb, NFACCT_PKTS, cpu_to_be64(pkts)) ||
157             nla_put_be64(skb, NFACCT_BYTES, cpu_to_be64(bytes)) ||
158             nla_put_be32(skb, NFACCT_USE, htonl(atomic_read(&acct->refcnt))))
159                 goto nla_put_failure;
160         if (acct->flags & NFACCT_F_QUOTA) {
161                 u64 *quota = (u64 *)acct->data;
162
163                 if (nla_put_be32(skb, NFACCT_FLAGS, htonl(acct->flags)) ||
164                     nla_put_be64(skb, NFACCT_QUOTA, cpu_to_be64(*quota)))
165                         goto nla_put_failure;
166         }
167         nlmsg_end(skb, nlh);
168         return skb->len;
169
170 nlmsg_failure:
171 nla_put_failure:
172         nlmsg_cancel(skb, nlh);
173         return -1;
174 }
175
176 static int
177 nfnl_acct_dump(struct sk_buff *skb, struct netlink_callback *cb)
178 {
179         struct nf_acct *cur, *last;
180
181         if (cb->args[2])
182                 return 0;
183
184         last = (struct nf_acct *)cb->args[1];
185         if (cb->args[1])
186                 cb->args[1] = 0;
187
188         rcu_read_lock();
189         list_for_each_entry_rcu(cur, &nfnl_acct_list, head) {
190                 if (last) {
191                         if (cur != last)
192                                 continue;
193
194                         last = NULL;
195                 }
196                 if (nfnl_acct_fill_info(skb, NETLINK_CB(cb->skb).portid,
197                                        cb->nlh->nlmsg_seq,
198                                        NFNL_MSG_TYPE(cb->nlh->nlmsg_type),
199                                        NFNL_MSG_ACCT_NEW, cur) < 0) {
200                         cb->args[1] = (unsigned long)cur;
201                         break;
202                 }
203         }
204         if (!cb->args[1])
205                 cb->args[2] = 1;
206         rcu_read_unlock();
207         return skb->len;
208 }
209
210 static int
211 nfnl_acct_get(struct sock *nfnl, struct sk_buff *skb,
212              const struct nlmsghdr *nlh, const struct nlattr * const tb[])
213 {
214         int ret = -ENOENT;
215         struct nf_acct *cur;
216         char *acct_name;
217
218         if (nlh->nlmsg_flags & NLM_F_DUMP) {
219                 struct netlink_dump_control c = {
220                         .dump = nfnl_acct_dump,
221                 };
222                 return netlink_dump_start(nfnl, skb, nlh, &c);
223         }
224
225         if (!tb[NFACCT_NAME])
226                 return -EINVAL;
227         acct_name = nla_data(tb[NFACCT_NAME]);
228
229         list_for_each_entry(cur, &nfnl_acct_list, head) {
230                 struct sk_buff *skb2;
231
232                 if (strncmp(cur->name, acct_name, NFACCT_NAME_MAX)!= 0)
233                         continue;
234
235                 skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
236                 if (skb2 == NULL) {
237                         ret = -ENOMEM;
238                         break;
239                 }
240
241                 ret = nfnl_acct_fill_info(skb2, NETLINK_CB(skb).portid,
242                                          nlh->nlmsg_seq,
243                                          NFNL_MSG_TYPE(nlh->nlmsg_type),
244                                          NFNL_MSG_ACCT_NEW, cur);
245                 if (ret <= 0) {
246                         kfree_skb(skb2);
247                         break;
248                 }
249                 ret = netlink_unicast(nfnl, skb2, NETLINK_CB(skb).portid,
250                                         MSG_DONTWAIT);
251                 if (ret > 0)
252                         ret = 0;
253
254                 /* this avoids a loop in nfnetlink. */
255                 return ret == -EAGAIN ? -ENOBUFS : ret;
256         }
257         return ret;
258 }
259
260 /* try to delete object, fail if it is still in use. */
261 static int nfnl_acct_try_del(struct nf_acct *cur)
262 {
263         int ret = 0;
264
265         /* we want to avoid races with nfnl_acct_find_get. */
266         if (atomic_dec_and_test(&cur->refcnt)) {
267                 /* We are protected by nfnl mutex. */
268                 list_del_rcu(&cur->head);
269                 kfree_rcu(cur, rcu_head);
270         } else {
271                 /* still in use, restore reference counter. */
272                 atomic_inc(&cur->refcnt);
273                 ret = -EBUSY;
274         }
275         return ret;
276 }
277
278 static int
279 nfnl_acct_del(struct sock *nfnl, struct sk_buff *skb,
280              const struct nlmsghdr *nlh, const struct nlattr * const tb[])
281 {
282         char *acct_name;
283         struct nf_acct *cur;
284         int ret = -ENOENT;
285
286         if (!tb[NFACCT_NAME]) {
287                 list_for_each_entry(cur, &nfnl_acct_list, head)
288                         nfnl_acct_try_del(cur);
289
290                 return 0;
291         }
292         acct_name = nla_data(tb[NFACCT_NAME]);
293
294         list_for_each_entry(cur, &nfnl_acct_list, head) {
295                 if (strncmp(cur->name, acct_name, NFACCT_NAME_MAX) != 0)
296                         continue;
297
298                 ret = nfnl_acct_try_del(cur);
299                 if (ret < 0)
300                         return ret;
301
302                 break;
303         }
304         return ret;
305 }
306
307 static const struct nla_policy nfnl_acct_policy[NFACCT_MAX+1] = {
308         [NFACCT_NAME] = { .type = NLA_NUL_STRING, .len = NFACCT_NAME_MAX-1 },
309         [NFACCT_BYTES] = { .type = NLA_U64 },
310         [NFACCT_PKTS] = { .type = NLA_U64 },
311         [NFACCT_FLAGS] = { .type = NLA_U32 },
312         [NFACCT_QUOTA] = { .type = NLA_U64 },
313 };
314
315 static const struct nfnl_callback nfnl_acct_cb[NFNL_MSG_ACCT_MAX] = {
316         [NFNL_MSG_ACCT_NEW]             = { .call = nfnl_acct_new,
317                                             .attr_count = NFACCT_MAX,
318                                             .policy = nfnl_acct_policy },
319         [NFNL_MSG_ACCT_GET]             = { .call = nfnl_acct_get,
320                                             .attr_count = NFACCT_MAX,
321                                             .policy = nfnl_acct_policy },
322         [NFNL_MSG_ACCT_GET_CTRZERO]     = { .call = nfnl_acct_get,
323                                             .attr_count = NFACCT_MAX,
324                                             .policy = nfnl_acct_policy },
325         [NFNL_MSG_ACCT_DEL]             = { .call = nfnl_acct_del,
326                                             .attr_count = NFACCT_MAX,
327                                             .policy = nfnl_acct_policy },
328 };
329
330 static const struct nfnetlink_subsystem nfnl_acct_subsys = {
331         .name                           = "acct",
332         .subsys_id                      = NFNL_SUBSYS_ACCT,
333         .cb_count                       = NFNL_MSG_ACCT_MAX,
334         .cb                             = nfnl_acct_cb,
335 };
336
337 MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_ACCT);
338
339 struct nf_acct *nfnl_acct_find_get(const char *acct_name)
340 {
341         struct nf_acct *cur, *acct = NULL;
342
343         rcu_read_lock();
344         list_for_each_entry_rcu(cur, &nfnl_acct_list, head) {
345                 if (strncmp(cur->name, acct_name, NFACCT_NAME_MAX)!= 0)
346                         continue;
347
348                 if (!try_module_get(THIS_MODULE))
349                         goto err;
350
351                 if (!atomic_inc_not_zero(&cur->refcnt)) {
352                         module_put(THIS_MODULE);
353                         goto err;
354                 }
355
356                 acct = cur;
357                 break;
358         }
359 err:
360         rcu_read_unlock();
361         return acct;
362 }
363 EXPORT_SYMBOL_GPL(nfnl_acct_find_get);
364
365 void nfnl_acct_put(struct nf_acct *acct)
366 {
367         atomic_dec(&acct->refcnt);
368         module_put(THIS_MODULE);
369 }
370 EXPORT_SYMBOL_GPL(nfnl_acct_put);
371
372 void nfnl_acct_update(const struct sk_buff *skb, struct nf_acct *nfacct)
373 {
374         atomic64_inc(&nfacct->pkts);
375         atomic64_add(skb->len, &nfacct->bytes);
376 }
377 EXPORT_SYMBOL_GPL(nfnl_acct_update);
378
379 static void nfnl_overquota_report(struct nf_acct *nfacct)
380 {
381         int ret;
382         struct sk_buff *skb;
383
384         skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
385         if (skb == NULL)
386                 return;
387
388         ret = nfnl_acct_fill_info(skb, 0, 0, NFNL_MSG_ACCT_OVERQUOTA, 0,
389                                   nfacct);
390         if (ret <= 0) {
391                 kfree_skb(skb);
392                 return;
393         }
394         netlink_broadcast(init_net.nfnl, skb, 0, NFNLGRP_ACCT_QUOTA,
395                           GFP_ATOMIC);
396 }
397
398 int nfnl_acct_overquota(const struct sk_buff *skb, struct nf_acct *nfacct)
399 {
400         u64 now;
401         u64 *quota;
402         int ret = NFACCT_UNDERQUOTA;
403
404         /* no place here if we don't have a quota */
405         if (!(nfacct->flags & NFACCT_F_QUOTA))
406                 return NFACCT_NO_QUOTA;
407
408         quota = (u64 *)nfacct->data;
409         now = (nfacct->flags & NFACCT_F_QUOTA_PKTS) ?
410                atomic64_read(&nfacct->pkts) : atomic64_read(&nfacct->bytes);
411
412         ret = now > *quota;
413
414         if (now >= *quota &&
415             !test_and_set_bit(NFACCT_F_OVERQUOTA, &nfacct->flags)) {
416                 nfnl_overquota_report(nfacct);
417         }
418
419         return ret;
420 }
421 EXPORT_SYMBOL_GPL(nfnl_acct_overquota);
422
423 static int __init nfnl_acct_init(void)
424 {
425         int ret;
426
427         pr_info("nfnl_acct: registering with nfnetlink.\n");
428         ret = nfnetlink_subsys_register(&nfnl_acct_subsys);
429         if (ret < 0) {
430                 pr_err("nfnl_acct_init: cannot register with nfnetlink.\n");
431                 goto err_out;
432         }
433         return 0;
434 err_out:
435         return ret;
436 }
437
438 static void __exit nfnl_acct_exit(void)
439 {
440         struct nf_acct *cur, *tmp;
441
442         pr_info("nfnl_acct: unregistering from nfnetlink.\n");
443         nfnetlink_subsys_unregister(&nfnl_acct_subsys);
444
445         list_for_each_entry_safe(cur, tmp, &nfnl_acct_list, head) {
446                 list_del_rcu(&cur->head);
447                 /* We are sure that our objects have no clients at this point,
448                  * it's safe to release them all without checking refcnt. */
449                 kfree_rcu(cur, rcu_head);
450         }
451 }
452
453 module_init(nfnl_acct_init);
454 module_exit(nfnl_acct_exit);