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