Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * (C) 2012 Pablo Neira Ayuso <pablo@netfilter.org>
0004  *
0005  * This software has been sponsored by Vyatta Inc. <http://www.vyatta.com>
0006  */
0007 #include <linux/init.h>
0008 #include <linux/module.h>
0009 #include <linux/kernel.h>
0010 #include <linux/skbuff.h>
0011 #include <linux/netlink.h>
0012 #include <linux/rculist.h>
0013 #include <linux/slab.h>
0014 #include <linux/types.h>
0015 #include <linux/list.h>
0016 #include <linux/errno.h>
0017 #include <linux/capability.h>
0018 #include <net/netlink.h>
0019 #include <net/sock.h>
0020 
0021 #include <net/netfilter/nf_conntrack_helper.h>
0022 #include <net/netfilter/nf_conntrack_expect.h>
0023 #include <net/netfilter/nf_conntrack_ecache.h>
0024 
0025 #include <linux/netfilter/nfnetlink.h>
0026 #include <linux/netfilter/nfnetlink_conntrack.h>
0027 #include <linux/netfilter/nfnetlink_cthelper.h>
0028 
0029 MODULE_LICENSE("GPL");
0030 MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>");
0031 MODULE_DESCRIPTION("nfnl_cthelper: User-space connection tracking helpers");
0032 
0033 struct nfnl_cthelper {
0034     struct list_head        list;
0035     struct nf_conntrack_helper  helper;
0036 };
0037 
0038 static LIST_HEAD(nfnl_cthelper_list);
0039 
0040 static int
0041 nfnl_userspace_cthelper(struct sk_buff *skb, unsigned int protoff,
0042             struct nf_conn *ct, enum ip_conntrack_info ctinfo)
0043 {
0044     const struct nf_conn_help *help;
0045     struct nf_conntrack_helper *helper;
0046 
0047     help = nfct_help(ct);
0048     if (help == NULL)
0049         return NF_DROP;
0050 
0051     /* rcu_read_lock()ed by nf_hook_thresh */
0052     helper = rcu_dereference(help->helper);
0053     if (helper == NULL)
0054         return NF_DROP;
0055 
0056     /* This is a user-space helper not yet configured, skip. */
0057     if ((helper->flags &
0058         (NF_CT_HELPER_F_USERSPACE | NF_CT_HELPER_F_CONFIGURED)) ==
0059          NF_CT_HELPER_F_USERSPACE)
0060         return NF_ACCEPT;
0061 
0062     /* If the user-space helper is not available, don't block traffic. */
0063     return NF_QUEUE_NR(helper->queue_num) | NF_VERDICT_FLAG_QUEUE_BYPASS;
0064 }
0065 
0066 static const struct nla_policy nfnl_cthelper_tuple_pol[NFCTH_TUPLE_MAX+1] = {
0067     [NFCTH_TUPLE_L3PROTONUM] = { .type = NLA_U16, },
0068     [NFCTH_TUPLE_L4PROTONUM] = { .type = NLA_U8, },
0069 };
0070 
0071 static int
0072 nfnl_cthelper_parse_tuple(struct nf_conntrack_tuple *tuple,
0073               const struct nlattr *attr)
0074 {
0075     int err;
0076     struct nlattr *tb[NFCTH_TUPLE_MAX+1];
0077 
0078     err = nla_parse_nested_deprecated(tb, NFCTH_TUPLE_MAX, attr,
0079                       nfnl_cthelper_tuple_pol, NULL);
0080     if (err < 0)
0081         return err;
0082 
0083     if (!tb[NFCTH_TUPLE_L3PROTONUM] || !tb[NFCTH_TUPLE_L4PROTONUM])
0084         return -EINVAL;
0085 
0086     /* Not all fields are initialized so first zero the tuple */
0087     memset(tuple, 0, sizeof(struct nf_conntrack_tuple));
0088 
0089     tuple->src.l3num = ntohs(nla_get_be16(tb[NFCTH_TUPLE_L3PROTONUM]));
0090     tuple->dst.protonum = nla_get_u8(tb[NFCTH_TUPLE_L4PROTONUM]);
0091 
0092     return 0;
0093 }
0094 
0095 static int
0096 nfnl_cthelper_from_nlattr(struct nlattr *attr, struct nf_conn *ct)
0097 {
0098     struct nf_conn_help *help = nfct_help(ct);
0099     const struct nf_conntrack_helper *helper;
0100 
0101     if (attr == NULL)
0102         return -EINVAL;
0103 
0104     helper = rcu_dereference(help->helper);
0105     if (!helper || helper->data_len == 0)
0106         return -EINVAL;
0107 
0108     nla_memcpy(help->data, attr, sizeof(help->data));
0109     return 0;
0110 }
0111 
0112 static int
0113 nfnl_cthelper_to_nlattr(struct sk_buff *skb, const struct nf_conn *ct)
0114 {
0115     const struct nf_conn_help *help = nfct_help(ct);
0116     const struct nf_conntrack_helper *helper;
0117 
0118     helper = rcu_dereference(help->helper);
0119     if (helper && helper->data_len &&
0120         nla_put(skb, CTA_HELP_INFO, helper->data_len, &help->data))
0121         goto nla_put_failure;
0122 
0123     return 0;
0124 
0125 nla_put_failure:
0126     return -ENOSPC;
0127 }
0128 
0129 static const struct nla_policy nfnl_cthelper_expect_pol[NFCTH_POLICY_MAX+1] = {
0130     [NFCTH_POLICY_NAME] = { .type = NLA_NUL_STRING,
0131                 .len = NF_CT_HELPER_NAME_LEN-1 },
0132     [NFCTH_POLICY_EXPECT_MAX] = { .type = NLA_U32, },
0133     [NFCTH_POLICY_EXPECT_TIMEOUT] = { .type = NLA_U32, },
0134 };
0135 
0136 static int
0137 nfnl_cthelper_expect_policy(struct nf_conntrack_expect_policy *expect_policy,
0138                 const struct nlattr *attr)
0139 {
0140     int err;
0141     struct nlattr *tb[NFCTH_POLICY_MAX+1];
0142 
0143     err = nla_parse_nested_deprecated(tb, NFCTH_POLICY_MAX, attr,
0144                       nfnl_cthelper_expect_pol, NULL);
0145     if (err < 0)
0146         return err;
0147 
0148     if (!tb[NFCTH_POLICY_NAME] ||
0149         !tb[NFCTH_POLICY_EXPECT_MAX] ||
0150         !tb[NFCTH_POLICY_EXPECT_TIMEOUT])
0151         return -EINVAL;
0152 
0153     nla_strscpy(expect_policy->name,
0154             tb[NFCTH_POLICY_NAME], NF_CT_HELPER_NAME_LEN);
0155     expect_policy->max_expected =
0156         ntohl(nla_get_be32(tb[NFCTH_POLICY_EXPECT_MAX]));
0157     if (expect_policy->max_expected > NF_CT_EXPECT_MAX_CNT)
0158         return -EINVAL;
0159 
0160     expect_policy->timeout =
0161         ntohl(nla_get_be32(tb[NFCTH_POLICY_EXPECT_TIMEOUT]));
0162 
0163     return 0;
0164 }
0165 
0166 static const struct nla_policy
0167 nfnl_cthelper_expect_policy_set[NFCTH_POLICY_SET_MAX+1] = {
0168     [NFCTH_POLICY_SET_NUM] = { .type = NLA_U32, },
0169 };
0170 
0171 static int
0172 nfnl_cthelper_parse_expect_policy(struct nf_conntrack_helper *helper,
0173                   const struct nlattr *attr)
0174 {
0175     int i, ret;
0176     struct nf_conntrack_expect_policy *expect_policy;
0177     struct nlattr *tb[NFCTH_POLICY_SET_MAX+1];
0178     unsigned int class_max;
0179 
0180     ret = nla_parse_nested_deprecated(tb, NFCTH_POLICY_SET_MAX, attr,
0181                       nfnl_cthelper_expect_policy_set,
0182                       NULL);
0183     if (ret < 0)
0184         return ret;
0185 
0186     if (!tb[NFCTH_POLICY_SET_NUM])
0187         return -EINVAL;
0188 
0189     class_max = ntohl(nla_get_be32(tb[NFCTH_POLICY_SET_NUM]));
0190     if (class_max == 0)
0191         return -EINVAL;
0192     if (class_max > NF_CT_MAX_EXPECT_CLASSES)
0193         return -EOVERFLOW;
0194 
0195     expect_policy = kcalloc(class_max,
0196                 sizeof(struct nf_conntrack_expect_policy),
0197                 GFP_KERNEL);
0198     if (expect_policy == NULL)
0199         return -ENOMEM;
0200 
0201     for (i = 0; i < class_max; i++) {
0202         if (!tb[NFCTH_POLICY_SET+i])
0203             goto err;
0204 
0205         ret = nfnl_cthelper_expect_policy(&expect_policy[i],
0206                           tb[NFCTH_POLICY_SET+i]);
0207         if (ret < 0)
0208             goto err;
0209     }
0210 
0211     helper->expect_class_max = class_max - 1;
0212     helper->expect_policy = expect_policy;
0213     return 0;
0214 err:
0215     kfree(expect_policy);
0216     return -EINVAL;
0217 }
0218 
0219 static int
0220 nfnl_cthelper_create(const struct nlattr * const tb[],
0221              struct nf_conntrack_tuple *tuple)
0222 {
0223     struct nf_conntrack_helper *helper;
0224     struct nfnl_cthelper *nfcth;
0225     unsigned int size;
0226     int ret;
0227 
0228     if (!tb[NFCTH_TUPLE] || !tb[NFCTH_POLICY] || !tb[NFCTH_PRIV_DATA_LEN])
0229         return -EINVAL;
0230 
0231     nfcth = kzalloc(sizeof(*nfcth), GFP_KERNEL);
0232     if (nfcth == NULL)
0233         return -ENOMEM;
0234     helper = &nfcth->helper;
0235 
0236     ret = nfnl_cthelper_parse_expect_policy(helper, tb[NFCTH_POLICY]);
0237     if (ret < 0)
0238         goto err1;
0239 
0240     nla_strscpy(helper->name,
0241             tb[NFCTH_NAME], NF_CT_HELPER_NAME_LEN);
0242     size = ntohl(nla_get_be32(tb[NFCTH_PRIV_DATA_LEN]));
0243     if (size > sizeof_field(struct nf_conn_help, data)) {
0244         ret = -ENOMEM;
0245         goto err2;
0246     }
0247     helper->data_len = size;
0248 
0249     helper->flags |= NF_CT_HELPER_F_USERSPACE;
0250     memcpy(&helper->tuple, tuple, sizeof(struct nf_conntrack_tuple));
0251 
0252     helper->me = THIS_MODULE;
0253     helper->help = nfnl_userspace_cthelper;
0254     helper->from_nlattr = nfnl_cthelper_from_nlattr;
0255     helper->to_nlattr = nfnl_cthelper_to_nlattr;
0256 
0257     /* Default to queue number zero, this can be updated at any time. */
0258     if (tb[NFCTH_QUEUE_NUM])
0259         helper->queue_num = ntohl(nla_get_be32(tb[NFCTH_QUEUE_NUM]));
0260 
0261     if (tb[NFCTH_STATUS]) {
0262         int status = ntohl(nla_get_be32(tb[NFCTH_STATUS]));
0263 
0264         switch(status) {
0265         case NFCT_HELPER_STATUS_ENABLED:
0266             helper->flags |= NF_CT_HELPER_F_CONFIGURED;
0267             break;
0268         case NFCT_HELPER_STATUS_DISABLED:
0269             helper->flags &= ~NF_CT_HELPER_F_CONFIGURED;
0270             break;
0271         }
0272     }
0273 
0274     ret = nf_conntrack_helper_register(helper);
0275     if (ret < 0)
0276         goto err2;
0277 
0278     list_add_tail(&nfcth->list, &nfnl_cthelper_list);
0279     return 0;
0280 err2:
0281     kfree(helper->expect_policy);
0282 err1:
0283     kfree(nfcth);
0284     return ret;
0285 }
0286 
0287 static int
0288 nfnl_cthelper_update_policy_one(const struct nf_conntrack_expect_policy *policy,
0289                 struct nf_conntrack_expect_policy *new_policy,
0290                 const struct nlattr *attr)
0291 {
0292     struct nlattr *tb[NFCTH_POLICY_MAX + 1];
0293     int err;
0294 
0295     err = nla_parse_nested_deprecated(tb, NFCTH_POLICY_MAX, attr,
0296                       nfnl_cthelper_expect_pol, NULL);
0297     if (err < 0)
0298         return err;
0299 
0300     if (!tb[NFCTH_POLICY_NAME] ||
0301         !tb[NFCTH_POLICY_EXPECT_MAX] ||
0302         !tb[NFCTH_POLICY_EXPECT_TIMEOUT])
0303         return -EINVAL;
0304 
0305     if (nla_strcmp(tb[NFCTH_POLICY_NAME], policy->name))
0306         return -EBUSY;
0307 
0308     new_policy->max_expected =
0309         ntohl(nla_get_be32(tb[NFCTH_POLICY_EXPECT_MAX]));
0310     if (new_policy->max_expected > NF_CT_EXPECT_MAX_CNT)
0311         return -EINVAL;
0312 
0313     new_policy->timeout =
0314         ntohl(nla_get_be32(tb[NFCTH_POLICY_EXPECT_TIMEOUT]));
0315 
0316     return 0;
0317 }
0318 
0319 static int nfnl_cthelper_update_policy_all(struct nlattr *tb[],
0320                        struct nf_conntrack_helper *helper)
0321 {
0322     struct nf_conntrack_expect_policy *new_policy;
0323     struct nf_conntrack_expect_policy *policy;
0324     int i, ret = 0;
0325 
0326     new_policy = kmalloc_array(helper->expect_class_max + 1,
0327                    sizeof(*new_policy), GFP_KERNEL);
0328     if (!new_policy)
0329         return -ENOMEM;
0330 
0331     /* Check first that all policy attributes are well-formed, so we don't
0332      * leave things in inconsistent state on errors.
0333      */
0334     for (i = 0; i < helper->expect_class_max + 1; i++) {
0335 
0336         if (!tb[NFCTH_POLICY_SET + i]) {
0337             ret = -EINVAL;
0338             goto err;
0339         }
0340 
0341         ret = nfnl_cthelper_update_policy_one(&helper->expect_policy[i],
0342                               &new_policy[i],
0343                               tb[NFCTH_POLICY_SET + i]);
0344         if (ret < 0)
0345             goto err;
0346     }
0347     /* Now we can safely update them. */
0348     for (i = 0; i < helper->expect_class_max + 1; i++) {
0349         policy = (struct nf_conntrack_expect_policy *)
0350                 &helper->expect_policy[i];
0351         policy->max_expected = new_policy->max_expected;
0352         policy->timeout = new_policy->timeout;
0353     }
0354 
0355 err:
0356     kfree(new_policy);
0357     return ret;
0358 }
0359 
0360 static int nfnl_cthelper_update_policy(struct nf_conntrack_helper *helper,
0361                        const struct nlattr *attr)
0362 {
0363     struct nlattr *tb[NFCTH_POLICY_SET_MAX + 1];
0364     unsigned int class_max;
0365     int err;
0366 
0367     err = nla_parse_nested_deprecated(tb, NFCTH_POLICY_SET_MAX, attr,
0368                       nfnl_cthelper_expect_policy_set,
0369                       NULL);
0370     if (err < 0)
0371         return err;
0372 
0373     if (!tb[NFCTH_POLICY_SET_NUM])
0374         return -EINVAL;
0375 
0376     class_max = ntohl(nla_get_be32(tb[NFCTH_POLICY_SET_NUM]));
0377     if (helper->expect_class_max + 1 != class_max)
0378         return -EBUSY;
0379 
0380     return nfnl_cthelper_update_policy_all(tb, helper);
0381 }
0382 
0383 static int
0384 nfnl_cthelper_update(const struct nlattr * const tb[],
0385              struct nf_conntrack_helper *helper)
0386 {
0387     u32 size;
0388     int ret;
0389 
0390     if (tb[NFCTH_PRIV_DATA_LEN]) {
0391         size = ntohl(nla_get_be32(tb[NFCTH_PRIV_DATA_LEN]));
0392         if (size != helper->data_len)
0393             return -EBUSY;
0394     }
0395 
0396     if (tb[NFCTH_POLICY]) {
0397         ret = nfnl_cthelper_update_policy(helper, tb[NFCTH_POLICY]);
0398         if (ret < 0)
0399             return ret;
0400     }
0401     if (tb[NFCTH_QUEUE_NUM])
0402         helper->queue_num = ntohl(nla_get_be32(tb[NFCTH_QUEUE_NUM]));
0403 
0404     if (tb[NFCTH_STATUS]) {
0405         int status = ntohl(nla_get_be32(tb[NFCTH_STATUS]));
0406 
0407         switch(status) {
0408         case NFCT_HELPER_STATUS_ENABLED:
0409             helper->flags |= NF_CT_HELPER_F_CONFIGURED;
0410             break;
0411         case NFCT_HELPER_STATUS_DISABLED:
0412             helper->flags &= ~NF_CT_HELPER_F_CONFIGURED;
0413             break;
0414         }
0415     }
0416     return 0;
0417 }
0418 
0419 static int nfnl_cthelper_new(struct sk_buff *skb, const struct nfnl_info *info,
0420                  const struct nlattr * const tb[])
0421 {
0422     const char *helper_name;
0423     struct nf_conntrack_helper *cur, *helper = NULL;
0424     struct nf_conntrack_tuple tuple;
0425     struct nfnl_cthelper *nlcth;
0426     int ret = 0;
0427 
0428     if (!capable(CAP_NET_ADMIN))
0429         return -EPERM;
0430 
0431     if (!tb[NFCTH_NAME] || !tb[NFCTH_TUPLE])
0432         return -EINVAL;
0433 
0434     helper_name = nla_data(tb[NFCTH_NAME]);
0435 
0436     ret = nfnl_cthelper_parse_tuple(&tuple, tb[NFCTH_TUPLE]);
0437     if (ret < 0)
0438         return ret;
0439 
0440     list_for_each_entry(nlcth, &nfnl_cthelper_list, list) {
0441         cur = &nlcth->helper;
0442 
0443         if (strncmp(cur->name, helper_name, NF_CT_HELPER_NAME_LEN))
0444             continue;
0445 
0446         if ((tuple.src.l3num != cur->tuple.src.l3num ||
0447              tuple.dst.protonum != cur->tuple.dst.protonum))
0448             continue;
0449 
0450         if (info->nlh->nlmsg_flags & NLM_F_EXCL)
0451             return -EEXIST;
0452 
0453         helper = cur;
0454         break;
0455     }
0456 
0457     if (helper == NULL)
0458         ret = nfnl_cthelper_create(tb, &tuple);
0459     else
0460         ret = nfnl_cthelper_update(tb, helper);
0461 
0462     return ret;
0463 }
0464 
0465 static int
0466 nfnl_cthelper_dump_tuple(struct sk_buff *skb,
0467              struct nf_conntrack_helper *helper)
0468 {
0469     struct nlattr *nest_parms;
0470 
0471     nest_parms = nla_nest_start(skb, NFCTH_TUPLE);
0472     if (nest_parms == NULL)
0473         goto nla_put_failure;
0474 
0475     if (nla_put_be16(skb, NFCTH_TUPLE_L3PROTONUM,
0476              htons(helper->tuple.src.l3num)))
0477         goto nla_put_failure;
0478 
0479     if (nla_put_u8(skb, NFCTH_TUPLE_L4PROTONUM, helper->tuple.dst.protonum))
0480         goto nla_put_failure;
0481 
0482     nla_nest_end(skb, nest_parms);
0483     return 0;
0484 
0485 nla_put_failure:
0486     return -1;
0487 }
0488 
0489 static int
0490 nfnl_cthelper_dump_policy(struct sk_buff *skb,
0491             struct nf_conntrack_helper *helper)
0492 {
0493     int i;
0494     struct nlattr *nest_parms1, *nest_parms2;
0495 
0496     nest_parms1 = nla_nest_start(skb, NFCTH_POLICY);
0497     if (nest_parms1 == NULL)
0498         goto nla_put_failure;
0499 
0500     if (nla_put_be32(skb, NFCTH_POLICY_SET_NUM,
0501              htonl(helper->expect_class_max + 1)))
0502         goto nla_put_failure;
0503 
0504     for (i = 0; i < helper->expect_class_max + 1; i++) {
0505         nest_parms2 = nla_nest_start(skb, (NFCTH_POLICY_SET + i));
0506         if (nest_parms2 == NULL)
0507             goto nla_put_failure;
0508 
0509         if (nla_put_string(skb, NFCTH_POLICY_NAME,
0510                    helper->expect_policy[i].name))
0511             goto nla_put_failure;
0512 
0513         if (nla_put_be32(skb, NFCTH_POLICY_EXPECT_MAX,
0514                  htonl(helper->expect_policy[i].max_expected)))
0515             goto nla_put_failure;
0516 
0517         if (nla_put_be32(skb, NFCTH_POLICY_EXPECT_TIMEOUT,
0518                  htonl(helper->expect_policy[i].timeout)))
0519             goto nla_put_failure;
0520 
0521         nla_nest_end(skb, nest_parms2);
0522     }
0523     nla_nest_end(skb, nest_parms1);
0524     return 0;
0525 
0526 nla_put_failure:
0527     return -1;
0528 }
0529 
0530 static int
0531 nfnl_cthelper_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type,
0532             int event, struct nf_conntrack_helper *helper)
0533 {
0534     struct nlmsghdr *nlh;
0535     unsigned int flags = portid ? NLM_F_MULTI : 0;
0536     int status;
0537 
0538     event = nfnl_msg_type(NFNL_SUBSYS_CTHELPER, event);
0539     nlh = nfnl_msg_put(skb, portid, seq, event, flags, AF_UNSPEC,
0540                NFNETLINK_V0, 0);
0541     if (!nlh)
0542         goto nlmsg_failure;
0543 
0544     if (nla_put_string(skb, NFCTH_NAME, helper->name))
0545         goto nla_put_failure;
0546 
0547     if (nla_put_be32(skb, NFCTH_QUEUE_NUM, htonl(helper->queue_num)))
0548         goto nla_put_failure;
0549 
0550     if (nfnl_cthelper_dump_tuple(skb, helper) < 0)
0551         goto nla_put_failure;
0552 
0553     if (nfnl_cthelper_dump_policy(skb, helper) < 0)
0554         goto nla_put_failure;
0555 
0556     if (nla_put_be32(skb, NFCTH_PRIV_DATA_LEN, htonl(helper->data_len)))
0557         goto nla_put_failure;
0558 
0559     if (helper->flags & NF_CT_HELPER_F_CONFIGURED)
0560         status = NFCT_HELPER_STATUS_ENABLED;
0561     else
0562         status = NFCT_HELPER_STATUS_DISABLED;
0563 
0564     if (nla_put_be32(skb, NFCTH_STATUS, htonl(status)))
0565         goto nla_put_failure;
0566 
0567     nlmsg_end(skb, nlh);
0568     return skb->len;
0569 
0570 nlmsg_failure:
0571 nla_put_failure:
0572     nlmsg_cancel(skb, nlh);
0573     return -1;
0574 }
0575 
0576 static int
0577 nfnl_cthelper_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
0578 {
0579     struct nf_conntrack_helper *cur, *last;
0580 
0581     rcu_read_lock();
0582     last = (struct nf_conntrack_helper *)cb->args[1];
0583     for (; cb->args[0] < nf_ct_helper_hsize; cb->args[0]++) {
0584 restart:
0585         hlist_for_each_entry_rcu(cur,
0586                 &nf_ct_helper_hash[cb->args[0]], hnode) {
0587 
0588             /* skip non-userspace conntrack helpers. */
0589             if (!(cur->flags & NF_CT_HELPER_F_USERSPACE))
0590                 continue;
0591 
0592             if (cb->args[1]) {
0593                 if (cur != last)
0594                     continue;
0595                 cb->args[1] = 0;
0596             }
0597             if (nfnl_cthelper_fill_info(skb,
0598                         NETLINK_CB(cb->skb).portid,
0599                         cb->nlh->nlmsg_seq,
0600                         NFNL_MSG_TYPE(cb->nlh->nlmsg_type),
0601                         NFNL_MSG_CTHELPER_NEW, cur) < 0) {
0602                 cb->args[1] = (unsigned long)cur;
0603                 goto out;
0604             }
0605         }
0606     }
0607     if (cb->args[1]) {
0608         cb->args[1] = 0;
0609         goto restart;
0610     }
0611 out:
0612     rcu_read_unlock();
0613     return skb->len;
0614 }
0615 
0616 static int nfnl_cthelper_get(struct sk_buff *skb, const struct nfnl_info *info,
0617                  const struct nlattr * const tb[])
0618 {
0619     int ret = -ENOENT;
0620     struct nf_conntrack_helper *cur;
0621     struct sk_buff *skb2;
0622     char *helper_name = NULL;
0623     struct nf_conntrack_tuple tuple;
0624     struct nfnl_cthelper *nlcth;
0625     bool tuple_set = false;
0626 
0627     if (!capable(CAP_NET_ADMIN))
0628         return -EPERM;
0629 
0630     if (info->nlh->nlmsg_flags & NLM_F_DUMP) {
0631         struct netlink_dump_control c = {
0632             .dump = nfnl_cthelper_dump_table,
0633         };
0634         return netlink_dump_start(info->sk, skb, info->nlh, &c);
0635     }
0636 
0637     if (tb[NFCTH_NAME])
0638         helper_name = nla_data(tb[NFCTH_NAME]);
0639 
0640     if (tb[NFCTH_TUPLE]) {
0641         ret = nfnl_cthelper_parse_tuple(&tuple, tb[NFCTH_TUPLE]);
0642         if (ret < 0)
0643             return ret;
0644 
0645         tuple_set = true;
0646     }
0647 
0648     list_for_each_entry(nlcth, &nfnl_cthelper_list, list) {
0649         cur = &nlcth->helper;
0650         if (helper_name &&
0651             strncmp(cur->name, helper_name, NF_CT_HELPER_NAME_LEN))
0652             continue;
0653 
0654         if (tuple_set &&
0655             (tuple.src.l3num != cur->tuple.src.l3num ||
0656              tuple.dst.protonum != cur->tuple.dst.protonum))
0657             continue;
0658 
0659         skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
0660         if (skb2 == NULL) {
0661             ret = -ENOMEM;
0662             break;
0663         }
0664 
0665         ret = nfnl_cthelper_fill_info(skb2, NETLINK_CB(skb).portid,
0666                           info->nlh->nlmsg_seq,
0667                           NFNL_MSG_TYPE(info->nlh->nlmsg_type),
0668                           NFNL_MSG_CTHELPER_NEW, cur);
0669         if (ret <= 0) {
0670             kfree_skb(skb2);
0671             break;
0672         }
0673 
0674         ret = nfnetlink_unicast(skb2, info->net, NETLINK_CB(skb).portid);
0675         break;
0676     }
0677 
0678     return ret;
0679 }
0680 
0681 static int nfnl_cthelper_del(struct sk_buff *skb, const struct nfnl_info *info,
0682                  const struct nlattr * const tb[])
0683 {
0684     char *helper_name = NULL;
0685     struct nf_conntrack_helper *cur;
0686     struct nf_conntrack_tuple tuple;
0687     bool tuple_set = false, found = false;
0688     struct nfnl_cthelper *nlcth, *n;
0689     int j = 0, ret;
0690 
0691     if (!capable(CAP_NET_ADMIN))
0692         return -EPERM;
0693 
0694     if (tb[NFCTH_NAME])
0695         helper_name = nla_data(tb[NFCTH_NAME]);
0696 
0697     if (tb[NFCTH_TUPLE]) {
0698         ret = nfnl_cthelper_parse_tuple(&tuple, tb[NFCTH_TUPLE]);
0699         if (ret < 0)
0700             return ret;
0701 
0702         tuple_set = true;
0703     }
0704 
0705     ret = -ENOENT;
0706     list_for_each_entry_safe(nlcth, n, &nfnl_cthelper_list, list) {
0707         cur = &nlcth->helper;
0708         j++;
0709 
0710         if (helper_name &&
0711             strncmp(cur->name, helper_name, NF_CT_HELPER_NAME_LEN))
0712             continue;
0713 
0714         if (tuple_set &&
0715             (tuple.src.l3num != cur->tuple.src.l3num ||
0716              tuple.dst.protonum != cur->tuple.dst.protonum))
0717             continue;
0718 
0719         if (refcount_dec_if_one(&cur->refcnt)) {
0720             found = true;
0721             nf_conntrack_helper_unregister(cur);
0722             kfree(cur->expect_policy);
0723 
0724             list_del(&nlcth->list);
0725             kfree(nlcth);
0726         } else {
0727             ret = -EBUSY;
0728         }
0729     }
0730 
0731     /* Make sure we return success if we flush and there is no helpers */
0732     return (found || j == 0) ? 0 : ret;
0733 }
0734 
0735 static const struct nla_policy nfnl_cthelper_policy[NFCTH_MAX+1] = {
0736     [NFCTH_NAME] = { .type = NLA_NUL_STRING,
0737              .len = NF_CT_HELPER_NAME_LEN-1 },
0738     [NFCTH_QUEUE_NUM] = { .type = NLA_U32, },
0739     [NFCTH_PRIV_DATA_LEN] = { .type = NLA_U32, },
0740     [NFCTH_STATUS] = { .type = NLA_U32, },
0741 };
0742 
0743 static const struct nfnl_callback nfnl_cthelper_cb[NFNL_MSG_CTHELPER_MAX] = {
0744     [NFNL_MSG_CTHELPER_NEW] = {
0745         .call       = nfnl_cthelper_new,
0746         .type       = NFNL_CB_MUTEX,
0747         .attr_count = NFCTH_MAX,
0748         .policy     = nfnl_cthelper_policy
0749     },
0750     [NFNL_MSG_CTHELPER_GET] = {
0751         .call       = nfnl_cthelper_get,
0752         .type       = NFNL_CB_MUTEX,
0753         .attr_count = NFCTH_MAX,
0754         .policy     = nfnl_cthelper_policy
0755     },
0756     [NFNL_MSG_CTHELPER_DEL] = {
0757         .call       = nfnl_cthelper_del,
0758         .type       = NFNL_CB_MUTEX,
0759         .attr_count = NFCTH_MAX,
0760         .policy     = nfnl_cthelper_policy
0761     },
0762 };
0763 
0764 static const struct nfnetlink_subsystem nfnl_cthelper_subsys = {
0765     .name               = "cthelper",
0766     .subsys_id          = NFNL_SUBSYS_CTHELPER,
0767     .cb_count           = NFNL_MSG_CTHELPER_MAX,
0768     .cb             = nfnl_cthelper_cb,
0769 };
0770 
0771 MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_CTHELPER);
0772 
0773 static int __init nfnl_cthelper_init(void)
0774 {
0775     int ret;
0776 
0777     ret = nfnetlink_subsys_register(&nfnl_cthelper_subsys);
0778     if (ret < 0) {
0779         pr_err("nfnl_cthelper: cannot register with nfnetlink.\n");
0780         goto err_out;
0781     }
0782     return 0;
0783 err_out:
0784     return ret;
0785 }
0786 
0787 static void __exit nfnl_cthelper_exit(void)
0788 {
0789     struct nf_conntrack_helper *cur;
0790     struct nfnl_cthelper *nlcth, *n;
0791 
0792     nfnetlink_subsys_unregister(&nfnl_cthelper_subsys);
0793 
0794     list_for_each_entry_safe(nlcth, n, &nfnl_cthelper_list, list) {
0795         cur = &nlcth->helper;
0796 
0797         nf_conntrack_helper_unregister(cur);
0798         kfree(cur->expect_policy);
0799         kfree(nlcth);
0800     }
0801 }
0802 
0803 module_init(nfnl_cthelper_init);
0804 module_exit(nfnl_cthelper_exit);