Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * (C) 2011 Pablo Neira Ayuso <pablo@netfilter.org>
0004  * (C) 2011 Intra2net AG <https://www.intra2net.com>
0005  */
0006 #include <linux/init.h>
0007 #include <linux/module.h>
0008 #include <linux/kernel.h>
0009 #include <linux/skbuff.h>
0010 #include <linux/atomic.h>
0011 #include <linux/refcount.h>
0012 #include <linux/netlink.h>
0013 #include <linux/rculist.h>
0014 #include <linux/slab.h>
0015 #include <linux/types.h>
0016 #include <linux/errno.h>
0017 #include <net/netlink.h>
0018 #include <net/sock.h>
0019 #include <net/netns/generic.h>
0020 
0021 #include <linux/netfilter.h>
0022 #include <linux/netfilter/nfnetlink.h>
0023 #include <linux/netfilter/nfnetlink_acct.h>
0024 
0025 MODULE_LICENSE("GPL");
0026 MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>");
0027 MODULE_DESCRIPTION("nfacct: Extended Netfilter accounting infrastructure");
0028 
0029 struct nf_acct {
0030     atomic64_t      pkts;
0031     atomic64_t      bytes;
0032     unsigned long       flags;
0033     struct list_head    head;
0034     refcount_t      refcnt;
0035     char            name[NFACCT_NAME_MAX];
0036     struct rcu_head     rcu_head;
0037     char            data[];
0038 };
0039 
0040 struct nfacct_filter {
0041     u32 value;
0042     u32 mask;
0043 };
0044 
0045 struct nfnl_acct_net {
0046     struct list_head        nfnl_acct_list;
0047 };
0048 
0049 static unsigned int nfnl_acct_net_id __read_mostly;
0050 
0051 static inline struct nfnl_acct_net *nfnl_acct_pernet(struct net *net)
0052 {
0053     return net_generic(net, nfnl_acct_net_id);
0054 }
0055 
0056 #define NFACCT_F_QUOTA (NFACCT_F_QUOTA_PKTS | NFACCT_F_QUOTA_BYTES)
0057 #define NFACCT_OVERQUOTA_BIT    2   /* NFACCT_F_OVERQUOTA */
0058 
0059 static int nfnl_acct_new(struct sk_buff *skb, const struct nfnl_info *info,
0060              const struct nlattr * const tb[])
0061 {
0062     struct nfnl_acct_net *nfnl_acct_net = nfnl_acct_pernet(info->net);
0063     struct nf_acct *nfacct, *matching = NULL;
0064     unsigned int size = 0;
0065     char *acct_name;
0066     u32 flags = 0;
0067 
0068     if (!tb[NFACCT_NAME])
0069         return -EINVAL;
0070 
0071     acct_name = nla_data(tb[NFACCT_NAME]);
0072     if (strlen(acct_name) == 0)
0073         return -EINVAL;
0074 
0075     list_for_each_entry(nfacct, &nfnl_acct_net->nfnl_acct_list, head) {
0076         if (strncmp(nfacct->name, acct_name, NFACCT_NAME_MAX) != 0)
0077             continue;
0078 
0079                 if (info->nlh->nlmsg_flags & NLM_F_EXCL)
0080             return -EEXIST;
0081 
0082         matching = nfacct;
0083         break;
0084         }
0085 
0086     if (matching) {
0087         if (info->nlh->nlmsg_flags & NLM_F_REPLACE) {
0088             /* reset counters if you request a replacement. */
0089             atomic64_set(&matching->pkts, 0);
0090             atomic64_set(&matching->bytes, 0);
0091             smp_mb__before_atomic();
0092             /* reset overquota flag if quota is enabled. */
0093             if ((matching->flags & NFACCT_F_QUOTA))
0094                 clear_bit(NFACCT_OVERQUOTA_BIT,
0095                       &matching->flags);
0096             return 0;
0097         }
0098         return -EBUSY;
0099     }
0100 
0101     if (tb[NFACCT_FLAGS]) {
0102         flags = ntohl(nla_get_be32(tb[NFACCT_FLAGS]));
0103         if (flags & ~NFACCT_F_QUOTA)
0104             return -EOPNOTSUPP;
0105         if ((flags & NFACCT_F_QUOTA) == NFACCT_F_QUOTA)
0106             return -EINVAL;
0107         if (flags & NFACCT_F_OVERQUOTA)
0108             return -EINVAL;
0109         if ((flags & NFACCT_F_QUOTA) && !tb[NFACCT_QUOTA])
0110             return -EINVAL;
0111 
0112         size += sizeof(u64);
0113     }
0114 
0115     nfacct = kzalloc(sizeof(struct nf_acct) + size, GFP_KERNEL);
0116     if (nfacct == NULL)
0117         return -ENOMEM;
0118 
0119     if (flags & NFACCT_F_QUOTA) {
0120         u64 *quota = (u64 *)nfacct->data;
0121 
0122         *quota = be64_to_cpu(nla_get_be64(tb[NFACCT_QUOTA]));
0123         nfacct->flags = flags;
0124     }
0125 
0126     nla_strscpy(nfacct->name, tb[NFACCT_NAME], NFACCT_NAME_MAX);
0127 
0128     if (tb[NFACCT_BYTES]) {
0129         atomic64_set(&nfacct->bytes,
0130                  be64_to_cpu(nla_get_be64(tb[NFACCT_BYTES])));
0131     }
0132     if (tb[NFACCT_PKTS]) {
0133         atomic64_set(&nfacct->pkts,
0134                  be64_to_cpu(nla_get_be64(tb[NFACCT_PKTS])));
0135     }
0136     refcount_set(&nfacct->refcnt, 1);
0137     list_add_tail_rcu(&nfacct->head, &nfnl_acct_net->nfnl_acct_list);
0138     return 0;
0139 }
0140 
0141 static int
0142 nfnl_acct_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type,
0143            int event, struct nf_acct *acct)
0144 {
0145     struct nlmsghdr *nlh;
0146     unsigned int flags = portid ? NLM_F_MULTI : 0;
0147     u64 pkts, bytes;
0148     u32 old_flags;
0149 
0150     event = nfnl_msg_type(NFNL_SUBSYS_ACCT, event);
0151     nlh = nfnl_msg_put(skb, portid, seq, event, flags, AF_UNSPEC,
0152                NFNETLINK_V0, 0);
0153     if (!nlh)
0154         goto nlmsg_failure;
0155 
0156     if (nla_put_string(skb, NFACCT_NAME, acct->name))
0157         goto nla_put_failure;
0158 
0159     old_flags = acct->flags;
0160     if (type == NFNL_MSG_ACCT_GET_CTRZERO) {
0161         pkts = atomic64_xchg(&acct->pkts, 0);
0162         bytes = atomic64_xchg(&acct->bytes, 0);
0163         smp_mb__before_atomic();
0164         if (acct->flags & NFACCT_F_QUOTA)
0165             clear_bit(NFACCT_OVERQUOTA_BIT, &acct->flags);
0166     } else {
0167         pkts = atomic64_read(&acct->pkts);
0168         bytes = atomic64_read(&acct->bytes);
0169     }
0170     if (nla_put_be64(skb, NFACCT_PKTS, cpu_to_be64(pkts),
0171              NFACCT_PAD) ||
0172         nla_put_be64(skb, NFACCT_BYTES, cpu_to_be64(bytes),
0173              NFACCT_PAD) ||
0174         nla_put_be32(skb, NFACCT_USE, htonl(refcount_read(&acct->refcnt))))
0175         goto nla_put_failure;
0176     if (acct->flags & NFACCT_F_QUOTA) {
0177         u64 *quota = (u64 *)acct->data;
0178 
0179         if (nla_put_be32(skb, NFACCT_FLAGS, htonl(old_flags)) ||
0180             nla_put_be64(skb, NFACCT_QUOTA, cpu_to_be64(*quota),
0181                  NFACCT_PAD))
0182             goto nla_put_failure;
0183     }
0184     nlmsg_end(skb, nlh);
0185     return skb->len;
0186 
0187 nlmsg_failure:
0188 nla_put_failure:
0189     nlmsg_cancel(skb, nlh);
0190     return -1;
0191 }
0192 
0193 static int
0194 nfnl_acct_dump(struct sk_buff *skb, struct netlink_callback *cb)
0195 {
0196     struct net *net = sock_net(skb->sk);
0197     struct nfnl_acct_net *nfnl_acct_net = nfnl_acct_pernet(net);
0198     struct nf_acct *cur, *last;
0199     const struct nfacct_filter *filter = cb->data;
0200 
0201     if (cb->args[2])
0202         return 0;
0203 
0204     last = (struct nf_acct *)cb->args[1];
0205     if (cb->args[1])
0206         cb->args[1] = 0;
0207 
0208     rcu_read_lock();
0209     list_for_each_entry_rcu(cur, &nfnl_acct_net->nfnl_acct_list, head) {
0210         if (last) {
0211             if (cur != last)
0212                 continue;
0213 
0214             last = NULL;
0215         }
0216 
0217         if (filter && (cur->flags & filter->mask) != filter->value)
0218             continue;
0219 
0220         if (nfnl_acct_fill_info(skb, NETLINK_CB(cb->skb).portid,
0221                        cb->nlh->nlmsg_seq,
0222                        NFNL_MSG_TYPE(cb->nlh->nlmsg_type),
0223                        NFNL_MSG_ACCT_NEW, cur) < 0) {
0224             cb->args[1] = (unsigned long)cur;
0225             break;
0226         }
0227     }
0228     if (!cb->args[1])
0229         cb->args[2] = 1;
0230     rcu_read_unlock();
0231     return skb->len;
0232 }
0233 
0234 static int nfnl_acct_done(struct netlink_callback *cb)
0235 {
0236     kfree(cb->data);
0237     return 0;
0238 }
0239 
0240 static const struct nla_policy filter_policy[NFACCT_FILTER_MAX + 1] = {
0241     [NFACCT_FILTER_MASK]    = { .type = NLA_U32 },
0242     [NFACCT_FILTER_VALUE]   = { .type = NLA_U32 },
0243 };
0244 
0245 static int nfnl_acct_start(struct netlink_callback *cb)
0246 {
0247     const struct nlattr *const attr = cb->data;
0248     struct nlattr *tb[NFACCT_FILTER_MAX + 1];
0249     struct nfacct_filter *filter;
0250     int err;
0251 
0252     if (!attr)
0253         return 0;
0254 
0255     err = nla_parse_nested_deprecated(tb, NFACCT_FILTER_MAX, attr,
0256                       filter_policy, NULL);
0257     if (err < 0)
0258         return err;
0259 
0260     if (!tb[NFACCT_FILTER_MASK] || !tb[NFACCT_FILTER_VALUE])
0261         return -EINVAL;
0262 
0263     filter = kzalloc(sizeof(struct nfacct_filter), GFP_KERNEL);
0264     if (!filter)
0265         return -ENOMEM;
0266 
0267     filter->mask = ntohl(nla_get_be32(tb[NFACCT_FILTER_MASK]));
0268     filter->value = ntohl(nla_get_be32(tb[NFACCT_FILTER_VALUE]));
0269     cb->data = filter;
0270 
0271     return 0;
0272 }
0273 
0274 static int nfnl_acct_get(struct sk_buff *skb, const struct nfnl_info *info,
0275              const struct nlattr * const tb[])
0276 {
0277     struct nfnl_acct_net *nfnl_acct_net = nfnl_acct_pernet(info->net);
0278     int ret = -ENOENT;
0279     struct nf_acct *cur;
0280     char *acct_name;
0281 
0282     if (info->nlh->nlmsg_flags & NLM_F_DUMP) {
0283         struct netlink_dump_control c = {
0284             .dump = nfnl_acct_dump,
0285             .start = nfnl_acct_start,
0286             .done = nfnl_acct_done,
0287             .data = (void *)tb[NFACCT_FILTER],
0288         };
0289 
0290         return netlink_dump_start(info->sk, skb, info->nlh, &c);
0291     }
0292 
0293     if (!tb[NFACCT_NAME])
0294         return -EINVAL;
0295     acct_name = nla_data(tb[NFACCT_NAME]);
0296 
0297     list_for_each_entry(cur, &nfnl_acct_net->nfnl_acct_list, head) {
0298         struct sk_buff *skb2;
0299 
0300         if (strncmp(cur->name, acct_name, NFACCT_NAME_MAX)!= 0)
0301             continue;
0302 
0303         skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
0304         if (skb2 == NULL) {
0305             ret = -ENOMEM;
0306             break;
0307         }
0308 
0309         ret = nfnl_acct_fill_info(skb2, NETLINK_CB(skb).portid,
0310                       info->nlh->nlmsg_seq,
0311                       NFNL_MSG_TYPE(info->nlh->nlmsg_type),
0312                       NFNL_MSG_ACCT_NEW, cur);
0313         if (ret <= 0) {
0314             kfree_skb(skb2);
0315             break;
0316         }
0317 
0318         ret = nfnetlink_unicast(skb2, info->net, NETLINK_CB(skb).portid);
0319         break;
0320     }
0321 
0322     return ret;
0323 }
0324 
0325 /* try to delete object, fail if it is still in use. */
0326 static int nfnl_acct_try_del(struct nf_acct *cur)
0327 {
0328     int ret = 0;
0329 
0330     /* We want to avoid races with nfnl_acct_put. So only when the current
0331      * refcnt is 1, we decrease it to 0.
0332      */
0333     if (refcount_dec_if_one(&cur->refcnt)) {
0334         /* We are protected by nfnl mutex. */
0335         list_del_rcu(&cur->head);
0336         kfree_rcu(cur, rcu_head);
0337     } else {
0338         ret = -EBUSY;
0339     }
0340     return ret;
0341 }
0342 
0343 static int nfnl_acct_del(struct sk_buff *skb, const struct nfnl_info *info,
0344              const struct nlattr * const tb[])
0345 {
0346     struct nfnl_acct_net *nfnl_acct_net = nfnl_acct_pernet(info->net);
0347     struct nf_acct *cur, *tmp;
0348     int ret = -ENOENT;
0349     char *acct_name;
0350 
0351     if (!tb[NFACCT_NAME]) {
0352         list_for_each_entry_safe(cur, tmp, &nfnl_acct_net->nfnl_acct_list, head)
0353             nfnl_acct_try_del(cur);
0354 
0355         return 0;
0356     }
0357     acct_name = nla_data(tb[NFACCT_NAME]);
0358 
0359     list_for_each_entry(cur, &nfnl_acct_net->nfnl_acct_list, head) {
0360         if (strncmp(cur->name, acct_name, NFACCT_NAME_MAX) != 0)
0361             continue;
0362 
0363         ret = nfnl_acct_try_del(cur);
0364         if (ret < 0)
0365             return ret;
0366 
0367         break;
0368     }
0369     return ret;
0370 }
0371 
0372 static const struct nla_policy nfnl_acct_policy[NFACCT_MAX+1] = {
0373     [NFACCT_NAME] = { .type = NLA_NUL_STRING, .len = NFACCT_NAME_MAX-1 },
0374     [NFACCT_BYTES] = { .type = NLA_U64 },
0375     [NFACCT_PKTS] = { .type = NLA_U64 },
0376     [NFACCT_FLAGS] = { .type = NLA_U32 },
0377     [NFACCT_QUOTA] = { .type = NLA_U64 },
0378     [NFACCT_FILTER] = {.type = NLA_NESTED },
0379 };
0380 
0381 static const struct nfnl_callback nfnl_acct_cb[NFNL_MSG_ACCT_MAX] = {
0382     [NFNL_MSG_ACCT_NEW] = {
0383         .call       = nfnl_acct_new,
0384         .type       = NFNL_CB_MUTEX,
0385         .attr_count = NFACCT_MAX,
0386         .policy     = nfnl_acct_policy
0387     },
0388     [NFNL_MSG_ACCT_GET] = {
0389         .call       = nfnl_acct_get,
0390         .type       = NFNL_CB_MUTEX,
0391         .attr_count = NFACCT_MAX,
0392         .policy     = nfnl_acct_policy
0393     },
0394     [NFNL_MSG_ACCT_GET_CTRZERO] = {
0395         .call       = nfnl_acct_get,
0396         .type       = NFNL_CB_MUTEX,
0397         .attr_count = NFACCT_MAX,
0398         .policy     = nfnl_acct_policy
0399     },
0400     [NFNL_MSG_ACCT_DEL] = {
0401         .call       = nfnl_acct_del,
0402         .type       = NFNL_CB_MUTEX,
0403         .attr_count = NFACCT_MAX,
0404         .policy     = nfnl_acct_policy
0405     },
0406 };
0407 
0408 static const struct nfnetlink_subsystem nfnl_acct_subsys = {
0409     .name               = "acct",
0410     .subsys_id          = NFNL_SUBSYS_ACCT,
0411     .cb_count           = NFNL_MSG_ACCT_MAX,
0412     .cb             = nfnl_acct_cb,
0413 };
0414 
0415 MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_ACCT);
0416 
0417 struct nf_acct *nfnl_acct_find_get(struct net *net, const char *acct_name)
0418 {
0419     struct nfnl_acct_net *nfnl_acct_net = nfnl_acct_pernet(net);
0420     struct nf_acct *cur, *acct = NULL;
0421 
0422     rcu_read_lock();
0423     list_for_each_entry_rcu(cur, &nfnl_acct_net->nfnl_acct_list, head) {
0424         if (strncmp(cur->name, acct_name, NFACCT_NAME_MAX)!= 0)
0425             continue;
0426 
0427         if (!try_module_get(THIS_MODULE))
0428             goto err;
0429 
0430         if (!refcount_inc_not_zero(&cur->refcnt)) {
0431             module_put(THIS_MODULE);
0432             goto err;
0433         }
0434 
0435         acct = cur;
0436         break;
0437     }
0438 err:
0439     rcu_read_unlock();
0440     return acct;
0441 }
0442 EXPORT_SYMBOL_GPL(nfnl_acct_find_get);
0443 
0444 void nfnl_acct_put(struct nf_acct *acct)
0445 {
0446     if (refcount_dec_and_test(&acct->refcnt))
0447         kfree_rcu(acct, rcu_head);
0448 
0449     module_put(THIS_MODULE);
0450 }
0451 EXPORT_SYMBOL_GPL(nfnl_acct_put);
0452 
0453 void nfnl_acct_update(const struct sk_buff *skb, struct nf_acct *nfacct)
0454 {
0455     atomic64_inc(&nfacct->pkts);
0456     atomic64_add(skb->len, &nfacct->bytes);
0457 }
0458 EXPORT_SYMBOL_GPL(nfnl_acct_update);
0459 
0460 static void nfnl_overquota_report(struct net *net, struct nf_acct *nfacct)
0461 {
0462     int ret;
0463     struct sk_buff *skb;
0464 
0465     skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
0466     if (skb == NULL)
0467         return;
0468 
0469     ret = nfnl_acct_fill_info(skb, 0, 0, NFNL_MSG_ACCT_OVERQUOTA, 0,
0470                   nfacct);
0471     if (ret <= 0) {
0472         kfree_skb(skb);
0473         return;
0474     }
0475     nfnetlink_broadcast(net, skb, 0, NFNLGRP_ACCT_QUOTA, GFP_ATOMIC);
0476 }
0477 
0478 int nfnl_acct_overquota(struct net *net, struct nf_acct *nfacct)
0479 {
0480     u64 now;
0481     u64 *quota;
0482     int ret = NFACCT_UNDERQUOTA;
0483 
0484     /* no place here if we don't have a quota */
0485     if (!(nfacct->flags & NFACCT_F_QUOTA))
0486         return NFACCT_NO_QUOTA;
0487 
0488     quota = (u64 *)nfacct->data;
0489     now = (nfacct->flags & NFACCT_F_QUOTA_PKTS) ?
0490            atomic64_read(&nfacct->pkts) : atomic64_read(&nfacct->bytes);
0491 
0492     ret = now > *quota;
0493 
0494     if (now >= *quota &&
0495         !test_and_set_bit(NFACCT_OVERQUOTA_BIT, &nfacct->flags)) {
0496         nfnl_overquota_report(net, nfacct);
0497     }
0498 
0499     return ret;
0500 }
0501 EXPORT_SYMBOL_GPL(nfnl_acct_overquota);
0502 
0503 static int __net_init nfnl_acct_net_init(struct net *net)
0504 {
0505     INIT_LIST_HEAD(&nfnl_acct_pernet(net)->nfnl_acct_list);
0506 
0507     return 0;
0508 }
0509 
0510 static void __net_exit nfnl_acct_net_exit(struct net *net)
0511 {
0512     struct nfnl_acct_net *nfnl_acct_net = nfnl_acct_pernet(net);
0513     struct nf_acct *cur, *tmp;
0514 
0515     list_for_each_entry_safe(cur, tmp, &nfnl_acct_net->nfnl_acct_list, head) {
0516         list_del_rcu(&cur->head);
0517 
0518         if (refcount_dec_and_test(&cur->refcnt))
0519             kfree_rcu(cur, rcu_head);
0520     }
0521 }
0522 
0523 static struct pernet_operations nfnl_acct_ops = {
0524         .init   = nfnl_acct_net_init,
0525         .exit   = nfnl_acct_net_exit,
0526         .id     = &nfnl_acct_net_id,
0527         .size   = sizeof(struct nfnl_acct_net),
0528 };
0529 
0530 static int __init nfnl_acct_init(void)
0531 {
0532     int ret;
0533 
0534     ret = register_pernet_subsys(&nfnl_acct_ops);
0535     if (ret < 0) {
0536         pr_err("nfnl_acct_init: failed to register pernet ops\n");
0537         goto err_out;
0538     }
0539 
0540     ret = nfnetlink_subsys_register(&nfnl_acct_subsys);
0541     if (ret < 0) {
0542         pr_err("nfnl_acct_init: cannot register with nfnetlink.\n");
0543         goto cleanup_pernet;
0544     }
0545     return 0;
0546 
0547 cleanup_pernet:
0548     unregister_pernet_subsys(&nfnl_acct_ops);
0549 err_out:
0550     return ret;
0551 }
0552 
0553 static void __exit nfnl_acct_exit(void)
0554 {
0555     nfnetlink_subsys_unregister(&nfnl_acct_subsys);
0556     unregister_pernet_subsys(&nfnl_acct_ops);
0557 }
0558 
0559 module_init(nfnl_acct_init);
0560 module_exit(nfnl_acct_exit);