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_strscpy(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_strscpy(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        u32 size;
 384        int ret;
 385
 386        if (tb[NFCTH_PRIV_DATA_LEN]) {
 387                size = ntohl(nla_get_be32(tb[NFCTH_PRIV_DATA_LEN]));
 388                if (size != helper->data_len)
 389                        return -EBUSY;
 390        }
 391
 392        if (tb[NFCTH_POLICY]) {
 393                ret = nfnl_cthelper_update_policy(helper, tb[NFCTH_POLICY]);
 394                if (ret < 0)
 395                        return ret;
 396        }
 397        if (tb[NFCTH_QUEUE_NUM])
 398                helper->queue_num = ntohl(nla_get_be32(tb[NFCTH_QUEUE_NUM]));
 399
 400        if (tb[NFCTH_STATUS]) {
 401                int status = ntohl(nla_get_be32(tb[NFCTH_STATUS]));
 402
 403                switch(status) {
 404                case NFCT_HELPER_STATUS_ENABLED:
 405                        helper->flags |= NF_CT_HELPER_F_CONFIGURED;
 406                        break;
 407                case NFCT_HELPER_STATUS_DISABLED:
 408                        helper->flags &= ~NF_CT_HELPER_F_CONFIGURED;
 409                        break;
 410                }
 411        }
 412        return 0;
 413}
 414
 415static int nfnl_cthelper_new(struct sk_buff *skb, const struct nfnl_info *info,
 416                             const struct nlattr * const tb[])
 417{
 418        const char *helper_name;
 419        struct nf_conntrack_helper *cur, *helper = NULL;
 420        struct nf_conntrack_tuple tuple;
 421        struct nfnl_cthelper *nlcth;
 422        int ret = 0;
 423
 424        if (!capable(CAP_NET_ADMIN))
 425                return -EPERM;
 426
 427        if (!tb[NFCTH_NAME] || !tb[NFCTH_TUPLE])
 428                return -EINVAL;
 429
 430        helper_name = nla_data(tb[NFCTH_NAME]);
 431
 432        ret = nfnl_cthelper_parse_tuple(&tuple, tb[NFCTH_TUPLE]);
 433        if (ret < 0)
 434                return ret;
 435
 436        list_for_each_entry(nlcth, &nfnl_cthelper_list, list) {
 437                cur = &nlcth->helper;
 438
 439                if (strncmp(cur->name, helper_name, NF_CT_HELPER_NAME_LEN))
 440                        continue;
 441
 442                if ((tuple.src.l3num != cur->tuple.src.l3num ||
 443                     tuple.dst.protonum != cur->tuple.dst.protonum))
 444                        continue;
 445
 446                if (info->nlh->nlmsg_flags & NLM_F_EXCL)
 447                        return -EEXIST;
 448
 449                helper = cur;
 450                break;
 451        }
 452
 453        if (helper == NULL)
 454                ret = nfnl_cthelper_create(tb, &tuple);
 455        else
 456                ret = nfnl_cthelper_update(tb, helper);
 457
 458        return ret;
 459}
 460
 461static int
 462nfnl_cthelper_dump_tuple(struct sk_buff *skb,
 463                         struct nf_conntrack_helper *helper)
 464{
 465        struct nlattr *nest_parms;
 466
 467        nest_parms = nla_nest_start(skb, NFCTH_TUPLE);
 468        if (nest_parms == NULL)
 469                goto nla_put_failure;
 470
 471        if (nla_put_be16(skb, NFCTH_TUPLE_L3PROTONUM,
 472                         htons(helper->tuple.src.l3num)))
 473                goto nla_put_failure;
 474
 475        if (nla_put_u8(skb, NFCTH_TUPLE_L4PROTONUM, helper->tuple.dst.protonum))
 476                goto nla_put_failure;
 477
 478        nla_nest_end(skb, nest_parms);
 479        return 0;
 480
 481nla_put_failure:
 482        return -1;
 483}
 484
 485static int
 486nfnl_cthelper_dump_policy(struct sk_buff *skb,
 487                        struct nf_conntrack_helper *helper)
 488{
 489        int i;
 490        struct nlattr *nest_parms1, *nest_parms2;
 491
 492        nest_parms1 = nla_nest_start(skb, NFCTH_POLICY);
 493        if (nest_parms1 == NULL)
 494                goto nla_put_failure;
 495
 496        if (nla_put_be32(skb, NFCTH_POLICY_SET_NUM,
 497                         htonl(helper->expect_class_max + 1)))
 498                goto nla_put_failure;
 499
 500        for (i = 0; i < helper->expect_class_max + 1; i++) {
 501                nest_parms2 = nla_nest_start(skb, (NFCTH_POLICY_SET + i));
 502                if (nest_parms2 == NULL)
 503                        goto nla_put_failure;
 504
 505                if (nla_put_string(skb, NFCTH_POLICY_NAME,
 506                                   helper->expect_policy[i].name))
 507                        goto nla_put_failure;
 508
 509                if (nla_put_be32(skb, NFCTH_POLICY_EXPECT_MAX,
 510                                 htonl(helper->expect_policy[i].max_expected)))
 511                        goto nla_put_failure;
 512
 513                if (nla_put_be32(skb, NFCTH_POLICY_EXPECT_TIMEOUT,
 514                                 htonl(helper->expect_policy[i].timeout)))
 515                        goto nla_put_failure;
 516
 517                nla_nest_end(skb, nest_parms2);
 518        }
 519        nla_nest_end(skb, nest_parms1);
 520        return 0;
 521
 522nla_put_failure:
 523        return -1;
 524}
 525
 526static int
 527nfnl_cthelper_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type,
 528                        int event, struct nf_conntrack_helper *helper)
 529{
 530        struct nlmsghdr *nlh;
 531        unsigned int flags = portid ? NLM_F_MULTI : 0;
 532        int status;
 533
 534        event = nfnl_msg_type(NFNL_SUBSYS_CTHELPER, event);
 535        nlh = nfnl_msg_put(skb, portid, seq, event, flags, AF_UNSPEC,
 536                           NFNETLINK_V0, 0);
 537        if (!nlh)
 538                goto nlmsg_failure;
 539
 540        if (nla_put_string(skb, NFCTH_NAME, helper->name))
 541                goto nla_put_failure;
 542
 543        if (nla_put_be32(skb, NFCTH_QUEUE_NUM, htonl(helper->queue_num)))
 544                goto nla_put_failure;
 545
 546        if (nfnl_cthelper_dump_tuple(skb, helper) < 0)
 547                goto nla_put_failure;
 548
 549        if (nfnl_cthelper_dump_policy(skb, helper) < 0)
 550                goto nla_put_failure;
 551
 552        if (nla_put_be32(skb, NFCTH_PRIV_DATA_LEN, htonl(helper->data_len)))
 553                goto nla_put_failure;
 554
 555        if (helper->flags & NF_CT_HELPER_F_CONFIGURED)
 556                status = NFCT_HELPER_STATUS_ENABLED;
 557        else
 558                status = NFCT_HELPER_STATUS_DISABLED;
 559
 560        if (nla_put_be32(skb, NFCTH_STATUS, htonl(status)))
 561                goto nla_put_failure;
 562
 563        nlmsg_end(skb, nlh);
 564        return skb->len;
 565
 566nlmsg_failure:
 567nla_put_failure:
 568        nlmsg_cancel(skb, nlh);
 569        return -1;
 570}
 571
 572static int
 573nfnl_cthelper_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
 574{
 575        struct nf_conntrack_helper *cur, *last;
 576
 577        rcu_read_lock();
 578        last = (struct nf_conntrack_helper *)cb->args[1];
 579        for (; cb->args[0] < nf_ct_helper_hsize; cb->args[0]++) {
 580restart:
 581                hlist_for_each_entry_rcu(cur,
 582                                &nf_ct_helper_hash[cb->args[0]], hnode) {
 583
 584                        /* skip non-userspace conntrack helpers. */
 585                        if (!(cur->flags & NF_CT_HELPER_F_USERSPACE))
 586                                continue;
 587
 588                        if (cb->args[1]) {
 589                                if (cur != last)
 590                                        continue;
 591                                cb->args[1] = 0;
 592                        }
 593                        if (nfnl_cthelper_fill_info(skb,
 594                                            NETLINK_CB(cb->skb).portid,
 595                                            cb->nlh->nlmsg_seq,
 596                                            NFNL_MSG_TYPE(cb->nlh->nlmsg_type),
 597                                            NFNL_MSG_CTHELPER_NEW, cur) < 0) {
 598                                cb->args[1] = (unsigned long)cur;
 599                                goto out;
 600                        }
 601                }
 602        }
 603        if (cb->args[1]) {
 604                cb->args[1] = 0;
 605                goto restart;
 606        }
 607out:
 608        rcu_read_unlock();
 609        return skb->len;
 610}
 611
 612static int nfnl_cthelper_get(struct sk_buff *skb, const struct nfnl_info *info,
 613                             const struct nlattr * const tb[])
 614{
 615        int ret = -ENOENT;
 616        struct nf_conntrack_helper *cur;
 617        struct sk_buff *skb2;
 618        char *helper_name = NULL;
 619        struct nf_conntrack_tuple tuple;
 620        struct nfnl_cthelper *nlcth;
 621        bool tuple_set = false;
 622
 623        if (!capable(CAP_NET_ADMIN))
 624                return -EPERM;
 625
 626        if (info->nlh->nlmsg_flags & NLM_F_DUMP) {
 627                struct netlink_dump_control c = {
 628                        .dump = nfnl_cthelper_dump_table,
 629                };
 630                return netlink_dump_start(info->sk, skb, info->nlh, &c);
 631        }
 632
 633        if (tb[NFCTH_NAME])
 634                helper_name = nla_data(tb[NFCTH_NAME]);
 635
 636        if (tb[NFCTH_TUPLE]) {
 637                ret = nfnl_cthelper_parse_tuple(&tuple, tb[NFCTH_TUPLE]);
 638                if (ret < 0)
 639                        return ret;
 640
 641                tuple_set = true;
 642        }
 643
 644        list_for_each_entry(nlcth, &nfnl_cthelper_list, list) {
 645                cur = &nlcth->helper;
 646                if (helper_name &&
 647                    strncmp(cur->name, helper_name, NF_CT_HELPER_NAME_LEN))
 648                        continue;
 649
 650                if (tuple_set &&
 651                    (tuple.src.l3num != cur->tuple.src.l3num ||
 652                     tuple.dst.protonum != cur->tuple.dst.protonum))
 653                        continue;
 654
 655                skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
 656                if (skb2 == NULL) {
 657                        ret = -ENOMEM;
 658                        break;
 659                }
 660
 661                ret = nfnl_cthelper_fill_info(skb2, NETLINK_CB(skb).portid,
 662                                              info->nlh->nlmsg_seq,
 663                                              NFNL_MSG_TYPE(info->nlh->nlmsg_type),
 664                                              NFNL_MSG_CTHELPER_NEW, cur);
 665                if (ret <= 0) {
 666                        kfree_skb(skb2);
 667                        break;
 668                }
 669
 670                ret = nfnetlink_unicast(skb2, info->net, NETLINK_CB(skb).portid);
 671                break;
 672        }
 673
 674        return ret;
 675}
 676
 677static int nfnl_cthelper_del(struct sk_buff *skb, const struct nfnl_info *info,
 678                             const struct nlattr * const tb[])
 679{
 680        char *helper_name = NULL;
 681        struct nf_conntrack_helper *cur;
 682        struct nf_conntrack_tuple tuple;
 683        bool tuple_set = false, found = false;
 684        struct nfnl_cthelper *nlcth, *n;
 685        int j = 0, ret;
 686
 687        if (!capable(CAP_NET_ADMIN))
 688                return -EPERM;
 689
 690        if (tb[NFCTH_NAME])
 691                helper_name = nla_data(tb[NFCTH_NAME]);
 692
 693        if (tb[NFCTH_TUPLE]) {
 694                ret = nfnl_cthelper_parse_tuple(&tuple, tb[NFCTH_TUPLE]);
 695                if (ret < 0)
 696                        return ret;
 697
 698                tuple_set = true;
 699        }
 700
 701        ret = -ENOENT;
 702        list_for_each_entry_safe(nlcth, n, &nfnl_cthelper_list, list) {
 703                cur = &nlcth->helper;
 704                j++;
 705
 706                if (helper_name &&
 707                    strncmp(cur->name, helper_name, NF_CT_HELPER_NAME_LEN))
 708                        continue;
 709
 710                if (tuple_set &&
 711                    (tuple.src.l3num != cur->tuple.src.l3num ||
 712                     tuple.dst.protonum != cur->tuple.dst.protonum))
 713                        continue;
 714
 715                if (refcount_dec_if_one(&cur->refcnt)) {
 716                        found = true;
 717                        nf_conntrack_helper_unregister(cur);
 718                        kfree(cur->expect_policy);
 719
 720                        list_del(&nlcth->list);
 721                        kfree(nlcth);
 722                } else {
 723                        ret = -EBUSY;
 724                }
 725        }
 726
 727        /* Make sure we return success if we flush and there is no helpers */
 728        return (found || j == 0) ? 0 : ret;
 729}
 730
 731static const struct nla_policy nfnl_cthelper_policy[NFCTH_MAX+1] = {
 732        [NFCTH_NAME] = { .type = NLA_NUL_STRING,
 733                         .len = NF_CT_HELPER_NAME_LEN-1 },
 734        [NFCTH_QUEUE_NUM] = { .type = NLA_U32, },
 735        [NFCTH_PRIV_DATA_LEN] = { .type = NLA_U32, },
 736        [NFCTH_STATUS] = { .type = NLA_U32, },
 737};
 738
 739static const struct nfnl_callback nfnl_cthelper_cb[NFNL_MSG_CTHELPER_MAX] = {
 740        [NFNL_MSG_CTHELPER_NEW] = {
 741                .call           = nfnl_cthelper_new,
 742                .type           = NFNL_CB_MUTEX,
 743                .attr_count     = NFCTH_MAX,
 744                .policy         = nfnl_cthelper_policy
 745        },
 746        [NFNL_MSG_CTHELPER_GET] = {
 747                .call           = nfnl_cthelper_get,
 748                .type           = NFNL_CB_MUTEX,
 749                .attr_count     = NFCTH_MAX,
 750                .policy         = nfnl_cthelper_policy
 751        },
 752        [NFNL_MSG_CTHELPER_DEL] = {
 753                .call           = nfnl_cthelper_del,
 754                .type           = NFNL_CB_MUTEX,
 755                .attr_count     = NFCTH_MAX,
 756                .policy         = nfnl_cthelper_policy
 757        },
 758};
 759
 760static const struct nfnetlink_subsystem nfnl_cthelper_subsys = {
 761        .name                           = "cthelper",
 762        .subsys_id                      = NFNL_SUBSYS_CTHELPER,
 763        .cb_count                       = NFNL_MSG_CTHELPER_MAX,
 764        .cb                             = nfnl_cthelper_cb,
 765};
 766
 767MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_CTHELPER);
 768
 769static int __init nfnl_cthelper_init(void)
 770{
 771        int ret;
 772
 773        ret = nfnetlink_subsys_register(&nfnl_cthelper_subsys);
 774        if (ret < 0) {
 775                pr_err("nfnl_cthelper: cannot register with nfnetlink.\n");
 776                goto err_out;
 777        }
 778        return 0;
 779err_out:
 780        return ret;
 781}
 782
 783static void __exit nfnl_cthelper_exit(void)
 784{
 785        struct nf_conntrack_helper *cur;
 786        struct nfnl_cthelper *nlcth, *n;
 787
 788        nfnetlink_subsys_unregister(&nfnl_cthelper_subsys);
 789
 790        list_for_each_entry_safe(nlcth, n, &nfnl_cthelper_list, list) {
 791                cur = &nlcth->helper;
 792
 793                nf_conntrack_helper_unregister(cur);
 794                kfree(cur->expect_policy);
 795                kfree(nlcth);
 796        }
 797}
 798
 799module_init(nfnl_cthelper_init);
 800module_exit(nfnl_cthelper_exit);
 801