linux/net/netfilter/nfnetlink_cthelper.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * (C) 2012 Pablo Neira Ayuso <pablo@netfilter.org>
   4 *
   5 * This software has been sponsored by Vyatta Inc. <http://www.vyatta.com>
   6 */
   7#include <linux/init.h>
   8#include <linux/module.h>
   9#include <linux/kernel.h>
  10#include <linux/skbuff.h>
  11#include <linux/netlink.h>
  12#include <linux/rculist.h>
  13#include <linux/slab.h>
  14#include <linux/types.h>
  15#include <linux/list.h>
  16#include <linux/errno.h>
  17#include <linux/capability.h>
  18#include <net/netlink.h>
  19#include <net/sock.h>
  20
  21#include <net/netfilter/nf_conntrack_helper.h>
  22#include <net/netfilter/nf_conntrack_expect.h>
  23#include <net/netfilter/nf_conntrack_ecache.h>
  24
  25#include <linux/netfilter/nfnetlink.h>
  26#include <linux/netfilter/nfnetlink_conntrack.h>
  27#include <linux/netfilter/nfnetlink_cthelper.h>
  28
  29MODULE_LICENSE("GPL");
  30MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>");
  31MODULE_DESCRIPTION("nfnl_cthelper: User-space connection tracking helpers");
  32
  33struct nfnl_cthelper {
  34        struct list_head                list;
  35        struct nf_conntrack_helper      helper;
  36};
  37
  38static LIST_HEAD(nfnl_cthelper_list);
  39
  40static int
  41nfnl_userspace_cthelper(struct sk_buff *skb, unsigned int protoff,
  42                        struct nf_conn *ct, enum ip_conntrack_info ctinfo)
  43{
  44        const struct nf_conn_help *help;
  45        struct nf_conntrack_helper *helper;
  46
  47        help = nfct_help(ct);
  48        if (help == NULL)
  49                return NF_DROP;
  50
  51        /* rcu_read_lock()ed by nf_hook_thresh */
  52        helper = rcu_dereference(help->helper);
  53        if (helper == NULL)
  54                return NF_DROP;
  55
  56        /* This is a user-space helper not yet configured, skip. */
  57        if ((helper->flags &
  58            (NF_CT_HELPER_F_USERSPACE | NF_CT_HELPER_F_CONFIGURED)) ==
  59             NF_CT_HELPER_F_USERSPACE)
  60                return NF_ACCEPT;
  61
  62        /* If the user-space helper is not available, don't block traffic. */
  63        return NF_QUEUE_NR(helper->queue_num) | NF_VERDICT_FLAG_QUEUE_BYPASS;
  64}
  65
  66static const struct nla_policy nfnl_cthelper_tuple_pol[NFCTH_TUPLE_MAX+1] = {
  67        [NFCTH_TUPLE_L3PROTONUM] = { .type = NLA_U16, },
  68        [NFCTH_TUPLE_L4PROTONUM] = { .type = NLA_U8, },
  69};
  70
  71static int
  72nfnl_cthelper_parse_tuple(struct nf_conntrack_tuple *tuple,
  73                          const struct nlattr *attr)
  74{
  75        int err;
  76        struct nlattr *tb[NFCTH_TUPLE_MAX+1];
  77
  78        err = nla_parse_nested_deprecated(tb, NFCTH_TUPLE_MAX, attr,
  79                                          nfnl_cthelper_tuple_pol, NULL);
  80        if (err < 0)
  81                return err;
  82
  83        if (!tb[NFCTH_TUPLE_L3PROTONUM] || !tb[NFCTH_TUPLE_L4PROTONUM])
  84                return -EINVAL;
  85
  86        /* Not all fields are initialized so first zero the tuple */
  87        memset(tuple, 0, sizeof(struct nf_conntrack_tuple));
  88
  89        tuple->src.l3num = ntohs(nla_get_be16(tb[NFCTH_TUPLE_L3PROTONUM]));
  90        tuple->dst.protonum = nla_get_u8(tb[NFCTH_TUPLE_L4PROTONUM]);
  91
  92        return 0;
  93}
  94
  95static int
  96nfnl_cthelper_from_nlattr(struct nlattr *attr, struct nf_conn *ct)
  97{
  98        struct nf_conn_help *help = nfct_help(ct);
  99
 100        if (attr == NULL)
 101                return -EINVAL;
 102
 103        if (help->helper->data_len == 0)
 104                return -EINVAL;
 105
 106        nla_memcpy(help->data, attr, sizeof(help->data));
 107        return 0;
 108}
 109
 110static int
 111nfnl_cthelper_to_nlattr(struct sk_buff *skb, const struct nf_conn *ct)
 112{
 113        const struct nf_conn_help *help = nfct_help(ct);
 114
 115        if (help->helper->data_len &&
 116            nla_put(skb, CTA_HELP_INFO, help->helper->data_len, &help->data))
 117                goto nla_put_failure;
 118
 119        return 0;
 120
 121nla_put_failure:
 122        return -ENOSPC;
 123}
 124
 125static const struct nla_policy nfnl_cthelper_expect_pol[NFCTH_POLICY_MAX+1] = {
 126        [NFCTH_POLICY_NAME] = { .type = NLA_NUL_STRING,
 127                                .len = NF_CT_HELPER_NAME_LEN-1 },
 128        [NFCTH_POLICY_EXPECT_MAX] = { .type = NLA_U32, },
 129        [NFCTH_POLICY_EXPECT_TIMEOUT] = { .type = NLA_U32, },
 130};
 131
 132static int
 133nfnl_cthelper_expect_policy(struct nf_conntrack_expect_policy *expect_policy,
 134                            const struct nlattr *attr)
 135{
 136        int err;
 137        struct nlattr *tb[NFCTH_POLICY_MAX+1];
 138
 139        err = nla_parse_nested_deprecated(tb, NFCTH_POLICY_MAX, attr,
 140                                          nfnl_cthelper_expect_pol, NULL);
 141        if (err < 0)
 142                return err;
 143
 144        if (!tb[NFCTH_POLICY_NAME] ||
 145            !tb[NFCTH_POLICY_EXPECT_MAX] ||
 146            !tb[NFCTH_POLICY_EXPECT_TIMEOUT])
 147                return -EINVAL;
 148
 149        nla_strlcpy(expect_policy->name,
 150                    tb[NFCTH_POLICY_NAME], NF_CT_HELPER_NAME_LEN);
 151        expect_policy->max_expected =
 152                ntohl(nla_get_be32(tb[NFCTH_POLICY_EXPECT_MAX]));
 153        if (expect_policy->max_expected > NF_CT_EXPECT_MAX_CNT)
 154                return -EINVAL;
 155
 156        expect_policy->timeout =
 157                ntohl(nla_get_be32(tb[NFCTH_POLICY_EXPECT_TIMEOUT]));
 158
 159        return 0;
 160}
 161
 162static const struct nla_policy
 163nfnl_cthelper_expect_policy_set[NFCTH_POLICY_SET_MAX+1] = {
 164        [NFCTH_POLICY_SET_NUM] = { .type = NLA_U32, },
 165};
 166
 167static int
 168nfnl_cthelper_parse_expect_policy(struct nf_conntrack_helper *helper,
 169                                  const struct nlattr *attr)
 170{
 171        int i, ret;
 172        struct nf_conntrack_expect_policy *expect_policy;
 173        struct nlattr *tb[NFCTH_POLICY_SET_MAX+1];
 174        unsigned int class_max;
 175
 176        ret = nla_parse_nested_deprecated(tb, NFCTH_POLICY_SET_MAX, attr,
 177                                          nfnl_cthelper_expect_policy_set,
 178                                          NULL);
 179        if (ret < 0)
 180                return ret;
 181
 182        if (!tb[NFCTH_POLICY_SET_NUM])
 183                return -EINVAL;
 184
 185        class_max = ntohl(nla_get_be32(tb[NFCTH_POLICY_SET_NUM]));
 186        if (class_max == 0)
 187                return -EINVAL;
 188        if (class_max > NF_CT_MAX_EXPECT_CLASSES)
 189                return -EOVERFLOW;
 190
 191        expect_policy = kcalloc(class_max,
 192                                sizeof(struct nf_conntrack_expect_policy),
 193                                GFP_KERNEL);
 194        if (expect_policy == NULL)
 195                return -ENOMEM;
 196
 197        for (i = 0; i < class_max; i++) {
 198                if (!tb[NFCTH_POLICY_SET+i])
 199                        goto err;
 200
 201                ret = nfnl_cthelper_expect_policy(&expect_policy[i],
 202                                                  tb[NFCTH_POLICY_SET+i]);
 203                if (ret < 0)
 204                        goto err;
 205        }
 206
 207        helper->expect_class_max = class_max - 1;
 208        helper->expect_policy = expect_policy;
 209        return 0;
 210err:
 211        kfree(expect_policy);
 212        return -EINVAL;
 213}
 214
 215static int
 216nfnl_cthelper_create(const struct nlattr * const tb[],
 217                     struct nf_conntrack_tuple *tuple)
 218{
 219        struct nf_conntrack_helper *helper;
 220        struct nfnl_cthelper *nfcth;
 221        unsigned int size;
 222        int ret;
 223
 224        if (!tb[NFCTH_TUPLE] || !tb[NFCTH_POLICY] || !tb[NFCTH_PRIV_DATA_LEN])
 225                return -EINVAL;
 226
 227        nfcth = kzalloc(sizeof(*nfcth), GFP_KERNEL);
 228        if (nfcth == NULL)
 229                return -ENOMEM;
 230        helper = &nfcth->helper;
 231
 232        ret = nfnl_cthelper_parse_expect_policy(helper, tb[NFCTH_POLICY]);
 233        if (ret < 0)
 234                goto err1;
 235
 236        nla_strlcpy(helper->name,
 237                    tb[NFCTH_NAME], NF_CT_HELPER_NAME_LEN);
 238        size = ntohl(nla_get_be32(tb[NFCTH_PRIV_DATA_LEN]));
 239        if (size > sizeof_field(struct nf_conn_help, data)) {
 240                ret = -ENOMEM;
 241                goto err2;
 242        }
 243        helper->data_len = size;
 244
 245        helper->flags |= NF_CT_HELPER_F_USERSPACE;
 246        memcpy(&helper->tuple, tuple, sizeof(struct nf_conntrack_tuple));
 247
 248        helper->me = THIS_MODULE;
 249        helper->help = nfnl_userspace_cthelper;
 250        helper->from_nlattr = nfnl_cthelper_from_nlattr;
 251        helper->to_nlattr = nfnl_cthelper_to_nlattr;
 252
 253        /* Default to queue number zero, this can be updated at any time. */
 254        if (tb[NFCTH_QUEUE_NUM])
 255                helper->queue_num = ntohl(nla_get_be32(tb[NFCTH_QUEUE_NUM]));
 256
 257        if (tb[NFCTH_STATUS]) {
 258                int status = ntohl(nla_get_be32(tb[NFCTH_STATUS]));
 259
 260                switch(status) {
 261                case NFCT_HELPER_STATUS_ENABLED:
 262                        helper->flags |= NF_CT_HELPER_F_CONFIGURED;
 263                        break;
 264                case NFCT_HELPER_STATUS_DISABLED:
 265                        helper->flags &= ~NF_CT_HELPER_F_CONFIGURED;
 266                        break;
 267                }
 268        }
 269
 270        ret = nf_conntrack_helper_register(helper);
 271        if (ret < 0)
 272                goto err2;
 273
 274        list_add_tail(&nfcth->list, &nfnl_cthelper_list);
 275        return 0;
 276err2:
 277        kfree(helper->expect_policy);
 278err1:
 279        kfree(nfcth);
 280        return ret;
 281}
 282
 283static int
 284nfnl_cthelper_update_policy_one(const struct nf_conntrack_expect_policy *policy,
 285                                struct nf_conntrack_expect_policy *new_policy,
 286                                const struct nlattr *attr)
 287{
 288        struct nlattr *tb[NFCTH_POLICY_MAX + 1];
 289        int err;
 290
 291        err = nla_parse_nested_deprecated(tb, NFCTH_POLICY_MAX, attr,
 292                                          nfnl_cthelper_expect_pol, NULL);
 293        if (err < 0)
 294                return err;
 295
 296        if (!tb[NFCTH_POLICY_NAME] ||
 297            !tb[NFCTH_POLICY_EXPECT_MAX] ||
 298            !tb[NFCTH_POLICY_EXPECT_TIMEOUT])
 299                return -EINVAL;
 300
 301        if (nla_strcmp(tb[NFCTH_POLICY_NAME], policy->name))
 302                return -EBUSY;
 303
 304        new_policy->max_expected =
 305                ntohl(nla_get_be32(tb[NFCTH_POLICY_EXPECT_MAX]));
 306        if (new_policy->max_expected > NF_CT_EXPECT_MAX_CNT)
 307                return -EINVAL;
 308
 309        new_policy->timeout =
 310                ntohl(nla_get_be32(tb[NFCTH_POLICY_EXPECT_TIMEOUT]));
 311
 312        return 0;
 313}
 314
 315static int nfnl_cthelper_update_policy_all(struct nlattr *tb[],
 316                                           struct nf_conntrack_helper *helper)
 317{
 318        struct nf_conntrack_expect_policy *new_policy;
 319        struct nf_conntrack_expect_policy *policy;
 320        int i, ret = 0;
 321
 322        new_policy = kmalloc_array(helper->expect_class_max + 1,
 323                                   sizeof(*new_policy), GFP_KERNEL);
 324        if (!new_policy)
 325                return -ENOMEM;
 326
 327        /* Check first that all policy attributes are well-formed, so we don't
 328         * leave things in inconsistent state on errors.
 329         */
 330        for (i = 0; i < helper->expect_class_max + 1; i++) {
 331
 332                if (!tb[NFCTH_POLICY_SET + i]) {
 333                        ret = -EINVAL;
 334                        goto err;
 335                }
 336
 337                ret = nfnl_cthelper_update_policy_one(&helper->expect_policy[i],
 338                                                      &new_policy[i],
 339                                                      tb[NFCTH_POLICY_SET + i]);
 340                if (ret < 0)
 341                        goto err;
 342        }
 343        /* Now we can safely update them. */
 344        for (i = 0; i < helper->expect_class_max + 1; i++) {
 345                policy = (struct nf_conntrack_expect_policy *)
 346                                &helper->expect_policy[i];
 347                policy->max_expected = new_policy->max_expected;
 348                policy->timeout = new_policy->timeout;
 349        }
 350
 351err:
 352        kfree(new_policy);
 353        return ret;
 354}
 355
 356static int nfnl_cthelper_update_policy(struct nf_conntrack_helper *helper,
 357                                       const struct nlattr *attr)
 358{
 359        struct nlattr *tb[NFCTH_POLICY_SET_MAX + 1];
 360        unsigned int class_max;
 361        int err;
 362
 363        err = nla_parse_nested_deprecated(tb, NFCTH_POLICY_SET_MAX, attr,
 364                                          nfnl_cthelper_expect_policy_set,
 365                                          NULL);
 366        if (err < 0)
 367                return err;
 368
 369        if (!tb[NFCTH_POLICY_SET_NUM])
 370                return -EINVAL;
 371
 372        class_max = ntohl(nla_get_be32(tb[NFCTH_POLICY_SET_NUM]));
 373        if (helper->expect_class_max + 1 != class_max)
 374                return -EBUSY;
 375
 376        return nfnl_cthelper_update_policy_all(tb, helper);
 377}
 378
 379static int
 380nfnl_cthelper_update(const struct nlattr * const tb[],
 381                     struct nf_conntrack_helper *helper)
 382{
 383        int ret;
 384
 385        if (tb[NFCTH_PRIV_DATA_LEN])
 386                return -EBUSY;
 387
 388        if (tb[NFCTH_POLICY]) {
 389                ret = nfnl_cthelper_update_policy(helper, tb[NFCTH_POLICY]);
 390                if (ret < 0)
 391                        return ret;
 392        }
 393        if (tb[NFCTH_QUEUE_NUM])
 394                helper->queue_num = ntohl(nla_get_be32(tb[NFCTH_QUEUE_NUM]));
 395
 396        if (tb[NFCTH_STATUS]) {
 397                int status = ntohl(nla_get_be32(tb[NFCTH_STATUS]));
 398
 399                switch(status) {
 400                case NFCT_HELPER_STATUS_ENABLED:
 401                        helper->flags |= NF_CT_HELPER_F_CONFIGURED;
 402                        break;
 403                case NFCT_HELPER_STATUS_DISABLED:
 404                        helper->flags &= ~NF_CT_HELPER_F_CONFIGURED;
 405                        break;
 406                }
 407        }
 408        return 0;
 409}
 410
 411static int nfnl_cthelper_new(struct net *net, struct sock *nfnl,
 412                             struct sk_buff *skb, const struct nlmsghdr *nlh,
 413                             const struct nlattr * const tb[],
 414                             struct netlink_ext_ack *extack)
 415{
 416        const char *helper_name;
 417        struct nf_conntrack_helper *cur, *helper = NULL;
 418        struct nf_conntrack_tuple tuple;
 419        struct nfnl_cthelper *nlcth;
 420        int ret = 0;
 421
 422        if (!capable(CAP_NET_ADMIN))
 423                return -EPERM;
 424
 425        if (!tb[NFCTH_NAME] || !tb[NFCTH_TUPLE])
 426                return -EINVAL;
 427
 428        helper_name = nla_data(tb[NFCTH_NAME]);
 429
 430        ret = nfnl_cthelper_parse_tuple(&tuple, tb[NFCTH_TUPLE]);
 431        if (ret < 0)
 432                return ret;
 433
 434        list_for_each_entry(nlcth, &nfnl_cthelper_list, list) {
 435                cur = &nlcth->helper;
 436
 437                if (strncmp(cur->name, helper_name, NF_CT_HELPER_NAME_LEN))
 438                        continue;
 439
 440                if ((tuple.src.l3num != cur->tuple.src.l3num ||
 441                     tuple.dst.protonum != cur->tuple.dst.protonum))
 442                        continue;
 443
 444                if (nlh->nlmsg_flags & NLM_F_EXCL)
 445                        return -EEXIST;
 446
 447                helper = cur;
 448                break;
 449        }
 450
 451        if (helper == NULL)
 452                ret = nfnl_cthelper_create(tb, &tuple);
 453        else
 454                ret = nfnl_cthelper_update(tb, helper);
 455
 456        return ret;
 457}
 458
 459static int
 460nfnl_cthelper_dump_tuple(struct sk_buff *skb,
 461                         struct nf_conntrack_helper *helper)
 462{
 463        struct nlattr *nest_parms;
 464
 465        nest_parms = nla_nest_start(skb, NFCTH_TUPLE);
 466        if (nest_parms == NULL)
 467                goto nla_put_failure;
 468
 469        if (nla_put_be16(skb, NFCTH_TUPLE_L3PROTONUM,
 470                         htons(helper->tuple.src.l3num)))
 471                goto nla_put_failure;
 472
 473        if (nla_put_u8(skb, NFCTH_TUPLE_L4PROTONUM, helper->tuple.dst.protonum))
 474                goto nla_put_failure;
 475
 476        nla_nest_end(skb, nest_parms);
 477        return 0;
 478
 479nla_put_failure:
 480        return -1;
 481}
 482
 483static int
 484nfnl_cthelper_dump_policy(struct sk_buff *skb,
 485                        struct nf_conntrack_helper *helper)
 486{
 487        int i;
 488        struct nlattr *nest_parms1, *nest_parms2;
 489
 490        nest_parms1 = nla_nest_start(skb, NFCTH_POLICY);
 491        if (nest_parms1 == NULL)
 492                goto nla_put_failure;
 493
 494        if (nla_put_be32(skb, NFCTH_POLICY_SET_NUM,
 495                         htonl(helper->expect_class_max + 1)))
 496                goto nla_put_failure;
 497
 498        for (i = 0; i < helper->expect_class_max + 1; i++) {
 499                nest_parms2 = nla_nest_start(skb, (NFCTH_POLICY_SET + i));
 500                if (nest_parms2 == NULL)
 501                        goto nla_put_failure;
 502
 503                if (nla_put_string(skb, NFCTH_POLICY_NAME,
 504                                   helper->expect_policy[i].name))
 505                        goto nla_put_failure;
 506
 507                if (nla_put_be32(skb, NFCTH_POLICY_EXPECT_MAX,
 508                                 htonl(helper->expect_policy[i].max_expected)))
 509                        goto nla_put_failure;
 510
 511                if (nla_put_be32(skb, NFCTH_POLICY_EXPECT_TIMEOUT,
 512                                 htonl(helper->expect_policy[i].timeout)))
 513                        goto nla_put_failure;
 514
 515                nla_nest_end(skb, nest_parms2);
 516        }
 517        nla_nest_end(skb, nest_parms1);
 518        return 0;
 519
 520nla_put_failure:
 521        return -1;
 522}
 523
 524static int
 525nfnl_cthelper_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type,
 526                        int event, struct nf_conntrack_helper *helper)
 527{
 528        struct nlmsghdr *nlh;
 529        struct nfgenmsg *nfmsg;
 530        unsigned int flags = portid ? NLM_F_MULTI : 0;
 531        int status;
 532
 533        event = nfnl_msg_type(NFNL_SUBSYS_CTHELPER, event);
 534        nlh = nlmsg_put(skb, portid, seq, event, sizeof(*nfmsg), flags);
 535        if (nlh == NULL)
 536                goto nlmsg_failure;
 537
 538        nfmsg = nlmsg_data(nlh);
 539        nfmsg->nfgen_family = AF_UNSPEC;
 540        nfmsg->version = NFNETLINK_V0;
 541        nfmsg->res_id = 0;
 542
 543        if (nla_put_string(skb, NFCTH_NAME, helper->name))
 544                goto nla_put_failure;
 545
 546        if (nla_put_be32(skb, NFCTH_QUEUE_NUM, htonl(helper->queue_num)))
 547                goto nla_put_failure;
 548
 549        if (nfnl_cthelper_dump_tuple(skb, helper) < 0)
 550                goto nla_put_failure;
 551
 552        if (nfnl_cthelper_dump_policy(skb, helper) < 0)
 553                goto nla_put_failure;
 554
 555        if (nla_put_be32(skb, NFCTH_PRIV_DATA_LEN, htonl(helper->data_len)))
 556                goto nla_put_failure;
 557
 558        if (helper->flags & NF_CT_HELPER_F_CONFIGURED)
 559                status = NFCT_HELPER_STATUS_ENABLED;
 560        else
 561                status = NFCT_HELPER_STATUS_DISABLED;
 562
 563        if (nla_put_be32(skb, NFCTH_STATUS, htonl(status)))
 564                goto nla_put_failure;
 565
 566        nlmsg_end(skb, nlh);
 567        return skb->len;
 568
 569nlmsg_failure:
 570nla_put_failure:
 571        nlmsg_cancel(skb, nlh);
 572        return -1;
 573}
 574
 575static int
 576nfnl_cthelper_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
 577{
 578        struct nf_conntrack_helper *cur, *last;
 579
 580        rcu_read_lock();
 581        last = (struct nf_conntrack_helper *)cb->args[1];
 582        for (; cb->args[0] < nf_ct_helper_hsize; cb->args[0]++) {
 583restart:
 584                hlist_for_each_entry_rcu(cur,
 585                                &nf_ct_helper_hash[cb->args[0]], hnode) {
 586
 587                        /* skip non-userspace conntrack helpers. */
 588                        if (!(cur->flags & NF_CT_HELPER_F_USERSPACE))
 589                                continue;
 590
 591                        if (cb->args[1]) {
 592                                if (cur != last)
 593                                        continue;
 594                                cb->args[1] = 0;
 595                        }
 596                        if (nfnl_cthelper_fill_info(skb,
 597                                            NETLINK_CB(cb->skb).portid,
 598                                            cb->nlh->nlmsg_seq,
 599                                            NFNL_MSG_TYPE(cb->nlh->nlmsg_type),
 600                                            NFNL_MSG_CTHELPER_NEW, cur) < 0) {
 601                                cb->args[1] = (unsigned long)cur;
 602                                goto out;
 603                        }
 604                }
 605        }
 606        if (cb->args[1]) {
 607                cb->args[1] = 0;
 608                goto restart;
 609        }
 610out:
 611        rcu_read_unlock();
 612        return skb->len;
 613}
 614
 615static int nfnl_cthelper_get(struct net *net, struct sock *nfnl,
 616                             struct sk_buff *skb, const struct nlmsghdr *nlh,
 617                             const struct nlattr * const tb[],
 618                             struct netlink_ext_ack *extack)
 619{
 620        int ret = -ENOENT;
 621        struct nf_conntrack_helper *cur;
 622        struct sk_buff *skb2;
 623        char *helper_name = NULL;
 624        struct nf_conntrack_tuple tuple;
 625        struct nfnl_cthelper *nlcth;
 626        bool tuple_set = false;
 627
 628        if (!capable(CAP_NET_ADMIN))
 629                return -EPERM;
 630
 631        if (nlh->nlmsg_flags & NLM_F_DUMP) {
 632                struct netlink_dump_control c = {
 633                        .dump = nfnl_cthelper_dump_table,
 634                };
 635                return netlink_dump_start(nfnl, skb, nlh, &c);
 636        }
 637
 638        if (tb[NFCTH_NAME])
 639                helper_name = nla_data(tb[NFCTH_NAME]);
 640
 641        if (tb[NFCTH_TUPLE]) {
 642                ret = nfnl_cthelper_parse_tuple(&tuple, tb[NFCTH_TUPLE]);
 643                if (ret < 0)
 644                        return ret;
 645
 646                tuple_set = true;
 647        }
 648
 649        list_for_each_entry(nlcth, &nfnl_cthelper_list, list) {
 650                cur = &nlcth->helper;
 651                if (helper_name &&
 652                    strncmp(cur->name, helper_name, NF_CT_HELPER_NAME_LEN))
 653                        continue;
 654
 655                if (tuple_set &&
 656                    (tuple.src.l3num != cur->tuple.src.l3num ||
 657                     tuple.dst.protonum != cur->tuple.dst.protonum))
 658                        continue;
 659
 660                skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
 661                if (skb2 == NULL) {
 662                        ret = -ENOMEM;
 663                        break;
 664                }
 665
 666                ret = nfnl_cthelper_fill_info(skb2, NETLINK_CB(skb).portid,
 667                                              nlh->nlmsg_seq,
 668                                              NFNL_MSG_TYPE(nlh->nlmsg_type),
 669                                              NFNL_MSG_CTHELPER_NEW, cur);
 670                if (ret <= 0) {
 671                        kfree_skb(skb2);
 672                        break;
 673                }
 674
 675                ret = netlink_unicast(nfnl, skb2, NETLINK_CB(skb).portid,
 676                                      MSG_DONTWAIT);
 677                if (ret > 0)
 678                        ret = 0;
 679
 680                /* this avoids a loop in nfnetlink. */
 681                return ret == -EAGAIN ? -ENOBUFS : ret;
 682        }
 683        return ret;
 684}
 685
 686static int nfnl_cthelper_del(struct net *net, struct sock *nfnl,
 687                             struct sk_buff *skb, const struct nlmsghdr *nlh,
 688                             const struct nlattr * const tb[],
 689                             struct netlink_ext_ack *extack)
 690{
 691        char *helper_name = NULL;
 692        struct nf_conntrack_helper *cur;
 693        struct nf_conntrack_tuple tuple;
 694        bool tuple_set = false, found = false;
 695        struct nfnl_cthelper *nlcth, *n;
 696        int j = 0, ret;
 697
 698        if (!capable(CAP_NET_ADMIN))
 699                return -EPERM;
 700
 701        if (tb[NFCTH_NAME])
 702                helper_name = nla_data(tb[NFCTH_NAME]);
 703
 704        if (tb[NFCTH_TUPLE]) {
 705                ret = nfnl_cthelper_parse_tuple(&tuple, tb[NFCTH_TUPLE]);
 706                if (ret < 0)
 707                        return ret;
 708
 709                tuple_set = true;
 710        }
 711
 712        ret = -ENOENT;
 713        list_for_each_entry_safe(nlcth, n, &nfnl_cthelper_list, list) {
 714                cur = &nlcth->helper;
 715                j++;
 716
 717                if (helper_name &&
 718                    strncmp(cur->name, helper_name, NF_CT_HELPER_NAME_LEN))
 719                        continue;
 720
 721                if (tuple_set &&
 722                    (tuple.src.l3num != cur->tuple.src.l3num ||
 723                     tuple.dst.protonum != cur->tuple.dst.protonum))
 724                        continue;
 725
 726                if (refcount_dec_if_one(&cur->refcnt)) {
 727                        found = true;
 728                        nf_conntrack_helper_unregister(cur);
 729                        kfree(cur->expect_policy);
 730
 731                        list_del(&nlcth->list);
 732                        kfree(nlcth);
 733                } else {
 734                        ret = -EBUSY;
 735                }
 736        }
 737
 738        /* Make sure we return success if we flush and there is no helpers */
 739        return (found || j == 0) ? 0 : ret;
 740}
 741
 742static const struct nla_policy nfnl_cthelper_policy[NFCTH_MAX+1] = {
 743        [NFCTH_NAME] = { .type = NLA_NUL_STRING,
 744                         .len = NF_CT_HELPER_NAME_LEN-1 },
 745        [NFCTH_QUEUE_NUM] = { .type = NLA_U32, },
 746        [NFCTH_PRIV_DATA_LEN] = { .type = NLA_U32, },
 747        [NFCTH_STATUS] = { .type = NLA_U32, },
 748};
 749
 750static const struct nfnl_callback nfnl_cthelper_cb[NFNL_MSG_CTHELPER_MAX] = {
 751        [NFNL_MSG_CTHELPER_NEW]         = { .call = nfnl_cthelper_new,
 752                                            .attr_count = NFCTH_MAX,
 753                                            .policy = nfnl_cthelper_policy },
 754        [NFNL_MSG_CTHELPER_GET]         = { .call = nfnl_cthelper_get,
 755                                            .attr_count = NFCTH_MAX,
 756                                            .policy = nfnl_cthelper_policy },
 757        [NFNL_MSG_CTHELPER_DEL]         = { .call = nfnl_cthelper_del,
 758                                            .attr_count = NFCTH_MAX,
 759                                            .policy = nfnl_cthelper_policy },
 760};
 761
 762static const struct nfnetlink_subsystem nfnl_cthelper_subsys = {
 763        .name                           = "cthelper",
 764        .subsys_id                      = NFNL_SUBSYS_CTHELPER,
 765        .cb_count                       = NFNL_MSG_CTHELPER_MAX,
 766        .cb                             = nfnl_cthelper_cb,
 767};
 768
 769MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_CTHELPER);
 770
 771static int __init nfnl_cthelper_init(void)
 772{
 773        int ret;
 774
 775        ret = nfnetlink_subsys_register(&nfnl_cthelper_subsys);
 776        if (ret < 0) {
 777                pr_err("nfnl_cthelper: cannot register with nfnetlink.\n");
 778                goto err_out;
 779        }
 780        return 0;
 781err_out:
 782        return ret;
 783}
 784
 785static void __exit nfnl_cthelper_exit(void)
 786{
 787        struct nf_conntrack_helper *cur;
 788        struct nfnl_cthelper *nlcth, *n;
 789
 790        nfnetlink_subsys_unregister(&nfnl_cthelper_subsys);
 791
 792        list_for_each_entry_safe(nlcth, n, &nfnl_cthelper_list, list) {
 793                cur = &nlcth->helper;
 794
 795                nf_conntrack_helper_unregister(cur);
 796                kfree(cur->expect_policy);
 797                kfree(nlcth);
 798        }
 799}
 800
 801module_init(nfnl_cthelper_init);
 802module_exit(nfnl_cthelper_exit);
 803