linux/net/netfilter/nft_ct.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
   3 * Copyright (c) 2016 Pablo Neira Ayuso <pablo@netfilter.org>
   4 *
   5 * This program is free software; you can redistribute it and/or modify
   6 * it under the terms of the GNU General Public License version 2 as
   7 * published by the Free Software Foundation.
   8 *
   9 * Development of this code funded by Astaro AG (http://www.astaro.com/)
  10 */
  11
  12#include <linux/kernel.h>
  13#include <linux/init.h>
  14#include <linux/module.h>
  15#include <linux/netlink.h>
  16#include <linux/netfilter.h>
  17#include <linux/netfilter/nf_tables.h>
  18#include <net/netfilter/nf_tables.h>
  19#include <net/netfilter/nf_conntrack.h>
  20#include <net/netfilter/nf_conntrack_acct.h>
  21#include <net/netfilter/nf_conntrack_tuple.h>
  22#include <net/netfilter/nf_conntrack_helper.h>
  23#include <net/netfilter/nf_conntrack_ecache.h>
  24#include <net/netfilter/nf_conntrack_labels.h>
  25
  26struct nft_ct {
  27        enum nft_ct_keys        key:8;
  28        enum ip_conntrack_dir   dir:8;
  29        union {
  30                enum nft_registers      dreg:8;
  31                enum nft_registers      sreg:8;
  32        };
  33};
  34
  35struct nft_ct_helper_obj  {
  36        struct nf_conntrack_helper *helper4;
  37        struct nf_conntrack_helper *helper6;
  38        u8 l4proto;
  39};
  40
  41#ifdef CONFIG_NF_CONNTRACK_ZONES
  42static DEFINE_PER_CPU(struct nf_conn *, nft_ct_pcpu_template);
  43static unsigned int nft_ct_pcpu_template_refcnt __read_mostly;
  44#endif
  45
  46static u64 nft_ct_get_eval_counter(const struct nf_conn_counter *c,
  47                                   enum nft_ct_keys k,
  48                                   enum ip_conntrack_dir d)
  49{
  50        if (d < IP_CT_DIR_MAX)
  51                return k == NFT_CT_BYTES ? atomic64_read(&c[d].bytes) :
  52                                           atomic64_read(&c[d].packets);
  53
  54        return nft_ct_get_eval_counter(c, k, IP_CT_DIR_ORIGINAL) +
  55               nft_ct_get_eval_counter(c, k, IP_CT_DIR_REPLY);
  56}
  57
  58static void nft_ct_get_eval(const struct nft_expr *expr,
  59                            struct nft_regs *regs,
  60                            const struct nft_pktinfo *pkt)
  61{
  62        const struct nft_ct *priv = nft_expr_priv(expr);
  63        u32 *dest = &regs->data[priv->dreg];
  64        enum ip_conntrack_info ctinfo;
  65        const struct nf_conn *ct;
  66        const struct nf_conn_help *help;
  67        const struct nf_conntrack_tuple *tuple;
  68        const struct nf_conntrack_helper *helper;
  69        unsigned int state;
  70
  71        ct = nf_ct_get(pkt->skb, &ctinfo);
  72
  73        switch (priv->key) {
  74        case NFT_CT_STATE:
  75                if (ct)
  76                        state = NF_CT_STATE_BIT(ctinfo);
  77                else if (ctinfo == IP_CT_UNTRACKED)
  78                        state = NF_CT_STATE_UNTRACKED_BIT;
  79                else
  80                        state = NF_CT_STATE_INVALID_BIT;
  81                *dest = state;
  82                return;
  83        default:
  84                break;
  85        }
  86
  87        if (ct == NULL)
  88                goto err;
  89
  90        switch (priv->key) {
  91        case NFT_CT_DIRECTION:
  92                nft_reg_store8(dest, CTINFO2DIR(ctinfo));
  93                return;
  94        case NFT_CT_STATUS:
  95                *dest = ct->status;
  96                return;
  97#ifdef CONFIG_NF_CONNTRACK_MARK
  98        case NFT_CT_MARK:
  99                *dest = ct->mark;
 100                return;
 101#endif
 102#ifdef CONFIG_NF_CONNTRACK_SECMARK
 103        case NFT_CT_SECMARK:
 104                *dest = ct->secmark;
 105                return;
 106#endif
 107        case NFT_CT_EXPIRATION:
 108                *dest = jiffies_to_msecs(nf_ct_expires(ct));
 109                return;
 110        case NFT_CT_HELPER:
 111                if (ct->master == NULL)
 112                        goto err;
 113                help = nfct_help(ct->master);
 114                if (help == NULL)
 115                        goto err;
 116                helper = rcu_dereference(help->helper);
 117                if (helper == NULL)
 118                        goto err;
 119                strncpy((char *)dest, helper->name, NF_CT_HELPER_NAME_LEN);
 120                return;
 121#ifdef CONFIG_NF_CONNTRACK_LABELS
 122        case NFT_CT_LABELS: {
 123                struct nf_conn_labels *labels = nf_ct_labels_find(ct);
 124
 125                if (labels)
 126                        memcpy(dest, labels->bits, NF_CT_LABELS_MAX_SIZE);
 127                else
 128                        memset(dest, 0, NF_CT_LABELS_MAX_SIZE);
 129                return;
 130        }
 131#endif
 132        case NFT_CT_BYTES: /* fallthrough */
 133        case NFT_CT_PKTS: {
 134                const struct nf_conn_acct *acct = nf_conn_acct_find(ct);
 135                u64 count = 0;
 136
 137                if (acct)
 138                        count = nft_ct_get_eval_counter(acct->counter,
 139                                                        priv->key, priv->dir);
 140                memcpy(dest, &count, sizeof(count));
 141                return;
 142        }
 143        case NFT_CT_AVGPKT: {
 144                const struct nf_conn_acct *acct = nf_conn_acct_find(ct);
 145                u64 avgcnt = 0, bcnt = 0, pcnt = 0;
 146
 147                if (acct) {
 148                        pcnt = nft_ct_get_eval_counter(acct->counter,
 149                                                       NFT_CT_PKTS, priv->dir);
 150                        bcnt = nft_ct_get_eval_counter(acct->counter,
 151                                                       NFT_CT_BYTES, priv->dir);
 152                        if (pcnt != 0)
 153                                avgcnt = div64_u64(bcnt, pcnt);
 154                }
 155
 156                memcpy(dest, &avgcnt, sizeof(avgcnt));
 157                return;
 158        }
 159        case NFT_CT_L3PROTOCOL:
 160                nft_reg_store8(dest, nf_ct_l3num(ct));
 161                return;
 162        case NFT_CT_PROTOCOL:
 163                nft_reg_store8(dest, nf_ct_protonum(ct));
 164                return;
 165#ifdef CONFIG_NF_CONNTRACK_ZONES
 166        case NFT_CT_ZONE: {
 167                const struct nf_conntrack_zone *zone = nf_ct_zone(ct);
 168                u16 zoneid;
 169
 170                if (priv->dir < IP_CT_DIR_MAX)
 171                        zoneid = nf_ct_zone_id(zone, priv->dir);
 172                else
 173                        zoneid = zone->id;
 174
 175                nft_reg_store16(dest, zoneid);
 176                return;
 177        }
 178#endif
 179        default:
 180                break;
 181        }
 182
 183        tuple = &ct->tuplehash[priv->dir].tuple;
 184        switch (priv->key) {
 185        case NFT_CT_SRC:
 186                memcpy(dest, tuple->src.u3.all,
 187                       nf_ct_l3num(ct) == NFPROTO_IPV4 ? 4 : 16);
 188                return;
 189        case NFT_CT_DST:
 190                memcpy(dest, tuple->dst.u3.all,
 191                       nf_ct_l3num(ct) == NFPROTO_IPV4 ? 4 : 16);
 192                return;
 193        case NFT_CT_PROTO_SRC:
 194                nft_reg_store16(dest, (__force u16)tuple->src.u.all);
 195                return;
 196        case NFT_CT_PROTO_DST:
 197                nft_reg_store16(dest, (__force u16)tuple->dst.u.all);
 198                return;
 199        default:
 200                break;
 201        }
 202        return;
 203err:
 204        regs->verdict.code = NFT_BREAK;
 205}
 206
 207#ifdef CONFIG_NF_CONNTRACK_ZONES
 208static void nft_ct_set_zone_eval(const struct nft_expr *expr,
 209                                 struct nft_regs *regs,
 210                                 const struct nft_pktinfo *pkt)
 211{
 212        struct nf_conntrack_zone zone = { .dir = NF_CT_DEFAULT_ZONE_DIR };
 213        const struct nft_ct *priv = nft_expr_priv(expr);
 214        struct sk_buff *skb = pkt->skb;
 215        enum ip_conntrack_info ctinfo;
 216        u16 value = nft_reg_load16(&regs->data[priv->sreg]);
 217        struct nf_conn *ct;
 218
 219        ct = nf_ct_get(skb, &ctinfo);
 220        if (ct) /* already tracked */
 221                return;
 222
 223        zone.id = value;
 224
 225        switch (priv->dir) {
 226        case IP_CT_DIR_ORIGINAL:
 227                zone.dir = NF_CT_ZONE_DIR_ORIG;
 228                break;
 229        case IP_CT_DIR_REPLY:
 230                zone.dir = NF_CT_ZONE_DIR_REPL;
 231                break;
 232        default:
 233                break;
 234        }
 235
 236        ct = this_cpu_read(nft_ct_pcpu_template);
 237
 238        if (likely(atomic_read(&ct->ct_general.use) == 1)) {
 239                nf_ct_zone_add(ct, &zone);
 240        } else {
 241                /* previous skb got queued to userspace */
 242                ct = nf_ct_tmpl_alloc(nft_net(pkt), &zone, GFP_ATOMIC);
 243                if (!ct) {
 244                        regs->verdict.code = NF_DROP;
 245                        return;
 246                }
 247        }
 248
 249        atomic_inc(&ct->ct_general.use);
 250        nf_ct_set(skb, ct, IP_CT_NEW);
 251}
 252#endif
 253
 254static void nft_ct_set_eval(const struct nft_expr *expr,
 255                            struct nft_regs *regs,
 256                            const struct nft_pktinfo *pkt)
 257{
 258        const struct nft_ct *priv = nft_expr_priv(expr);
 259        struct sk_buff *skb = pkt->skb;
 260#ifdef CONFIG_NF_CONNTRACK_MARK
 261        u32 value = regs->data[priv->sreg];
 262#endif
 263        enum ip_conntrack_info ctinfo;
 264        struct nf_conn *ct;
 265
 266        ct = nf_ct_get(skb, &ctinfo);
 267        if (ct == NULL || nf_ct_is_template(ct))
 268                return;
 269
 270        switch (priv->key) {
 271#ifdef CONFIG_NF_CONNTRACK_MARK
 272        case NFT_CT_MARK:
 273                if (ct->mark != value) {
 274                        ct->mark = value;
 275                        nf_conntrack_event_cache(IPCT_MARK, ct);
 276                }
 277                break;
 278#endif
 279#ifdef CONFIG_NF_CONNTRACK_LABELS
 280        case NFT_CT_LABELS:
 281                nf_connlabels_replace(ct,
 282                                      &regs->data[priv->sreg],
 283                                      &regs->data[priv->sreg],
 284                                      NF_CT_LABELS_MAX_SIZE / sizeof(u32));
 285                break;
 286#endif
 287#ifdef CONFIG_NF_CONNTRACK_EVENTS
 288        case NFT_CT_EVENTMASK: {
 289                struct nf_conntrack_ecache *e = nf_ct_ecache_find(ct);
 290                u32 ctmask = regs->data[priv->sreg];
 291
 292                if (e) {
 293                        if (e->ctmask != ctmask)
 294                                e->ctmask = ctmask;
 295                        break;
 296                }
 297
 298                if (ctmask && !nf_ct_is_confirmed(ct))
 299                        nf_ct_ecache_ext_add(ct, ctmask, 0, GFP_ATOMIC);
 300                break;
 301        }
 302#endif
 303        default:
 304                break;
 305        }
 306}
 307
 308static const struct nla_policy nft_ct_policy[NFTA_CT_MAX + 1] = {
 309        [NFTA_CT_DREG]          = { .type = NLA_U32 },
 310        [NFTA_CT_KEY]           = { .type = NLA_U32 },
 311        [NFTA_CT_DIRECTION]     = { .type = NLA_U8 },
 312        [NFTA_CT_SREG]          = { .type = NLA_U32 },
 313};
 314
 315static int nft_ct_netns_get(struct net *net, uint8_t family)
 316{
 317        int err;
 318
 319        if (family == NFPROTO_INET) {
 320                err = nf_ct_netns_get(net, NFPROTO_IPV4);
 321                if (err < 0)
 322                        goto err1;
 323                err = nf_ct_netns_get(net, NFPROTO_IPV6);
 324                if (err < 0)
 325                        goto err2;
 326        } else {
 327                err = nf_ct_netns_get(net, family);
 328                if (err < 0)
 329                        goto err1;
 330        }
 331        return 0;
 332
 333err2:
 334        nf_ct_netns_put(net, NFPROTO_IPV4);
 335err1:
 336        return err;
 337}
 338
 339static void nft_ct_netns_put(struct net *net, uint8_t family)
 340{
 341        if (family == NFPROTO_INET) {
 342                nf_ct_netns_put(net, NFPROTO_IPV4);
 343                nf_ct_netns_put(net, NFPROTO_IPV6);
 344        } else
 345                nf_ct_netns_put(net, family);
 346}
 347
 348#ifdef CONFIG_NF_CONNTRACK_ZONES
 349static void nft_ct_tmpl_put_pcpu(void)
 350{
 351        struct nf_conn *ct;
 352        int cpu;
 353
 354        for_each_possible_cpu(cpu) {
 355                ct = per_cpu(nft_ct_pcpu_template, cpu);
 356                if (!ct)
 357                        break;
 358                nf_ct_put(ct);
 359                per_cpu(nft_ct_pcpu_template, cpu) = NULL;
 360        }
 361}
 362
 363static bool nft_ct_tmpl_alloc_pcpu(void)
 364{
 365        struct nf_conntrack_zone zone = { .id = 0 };
 366        struct nf_conn *tmp;
 367        int cpu;
 368
 369        if (nft_ct_pcpu_template_refcnt)
 370                return true;
 371
 372        for_each_possible_cpu(cpu) {
 373                tmp = nf_ct_tmpl_alloc(&init_net, &zone, GFP_KERNEL);
 374                if (!tmp) {
 375                        nft_ct_tmpl_put_pcpu();
 376                        return false;
 377                }
 378
 379                atomic_set(&tmp->ct_general.use, 1);
 380                per_cpu(nft_ct_pcpu_template, cpu) = tmp;
 381        }
 382
 383        return true;
 384}
 385#endif
 386
 387static int nft_ct_get_init(const struct nft_ctx *ctx,
 388                           const struct nft_expr *expr,
 389                           const struct nlattr * const tb[])
 390{
 391        struct nft_ct *priv = nft_expr_priv(expr);
 392        unsigned int len;
 393        int err;
 394
 395        priv->key = ntohl(nla_get_be32(tb[NFTA_CT_KEY]));
 396        priv->dir = IP_CT_DIR_MAX;
 397        switch (priv->key) {
 398        case NFT_CT_DIRECTION:
 399                if (tb[NFTA_CT_DIRECTION] != NULL)
 400                        return -EINVAL;
 401                len = sizeof(u8);
 402                break;
 403        case NFT_CT_STATE:
 404        case NFT_CT_STATUS:
 405#ifdef CONFIG_NF_CONNTRACK_MARK
 406        case NFT_CT_MARK:
 407#endif
 408#ifdef CONFIG_NF_CONNTRACK_SECMARK
 409        case NFT_CT_SECMARK:
 410#endif
 411        case NFT_CT_EXPIRATION:
 412                if (tb[NFTA_CT_DIRECTION] != NULL)
 413                        return -EINVAL;
 414                len = sizeof(u32);
 415                break;
 416#ifdef CONFIG_NF_CONNTRACK_LABELS
 417        case NFT_CT_LABELS:
 418                if (tb[NFTA_CT_DIRECTION] != NULL)
 419                        return -EINVAL;
 420                len = NF_CT_LABELS_MAX_SIZE;
 421                break;
 422#endif
 423        case NFT_CT_HELPER:
 424                if (tb[NFTA_CT_DIRECTION] != NULL)
 425                        return -EINVAL;
 426                len = NF_CT_HELPER_NAME_LEN;
 427                break;
 428
 429        case NFT_CT_L3PROTOCOL:
 430        case NFT_CT_PROTOCOL:
 431                /* For compatibility, do not report error if NFTA_CT_DIRECTION
 432                 * attribute is specified.
 433                 */
 434                len = sizeof(u8);
 435                break;
 436        case NFT_CT_SRC:
 437        case NFT_CT_DST:
 438                if (tb[NFTA_CT_DIRECTION] == NULL)
 439                        return -EINVAL;
 440
 441                switch (ctx->afi->family) {
 442                case NFPROTO_IPV4:
 443                        len = FIELD_SIZEOF(struct nf_conntrack_tuple,
 444                                           src.u3.ip);
 445                        break;
 446                case NFPROTO_IPV6:
 447                case NFPROTO_INET:
 448                        len = FIELD_SIZEOF(struct nf_conntrack_tuple,
 449                                           src.u3.ip6);
 450                        break;
 451                default:
 452                        return -EAFNOSUPPORT;
 453                }
 454                break;
 455        case NFT_CT_PROTO_SRC:
 456        case NFT_CT_PROTO_DST:
 457                if (tb[NFTA_CT_DIRECTION] == NULL)
 458                        return -EINVAL;
 459                len = FIELD_SIZEOF(struct nf_conntrack_tuple, src.u.all);
 460                break;
 461        case NFT_CT_BYTES:
 462        case NFT_CT_PKTS:
 463        case NFT_CT_AVGPKT:
 464                len = sizeof(u64);
 465                break;
 466#ifdef CONFIG_NF_CONNTRACK_ZONES
 467        case NFT_CT_ZONE:
 468                len = sizeof(u16);
 469                break;
 470#endif
 471        default:
 472                return -EOPNOTSUPP;
 473        }
 474
 475        if (tb[NFTA_CT_DIRECTION] != NULL) {
 476                priv->dir = nla_get_u8(tb[NFTA_CT_DIRECTION]);
 477                switch (priv->dir) {
 478                case IP_CT_DIR_ORIGINAL:
 479                case IP_CT_DIR_REPLY:
 480                        break;
 481                default:
 482                        return -EINVAL;
 483                }
 484        }
 485
 486        priv->dreg = nft_parse_register(tb[NFTA_CT_DREG]);
 487        err = nft_validate_register_store(ctx, priv->dreg, NULL,
 488                                          NFT_DATA_VALUE, len);
 489        if (err < 0)
 490                return err;
 491
 492        err = nft_ct_netns_get(ctx->net, ctx->afi->family);
 493        if (err < 0)
 494                return err;
 495
 496        if (priv->key == NFT_CT_BYTES ||
 497            priv->key == NFT_CT_PKTS  ||
 498            priv->key == NFT_CT_AVGPKT)
 499                nf_ct_set_acct(ctx->net, true);
 500
 501        return 0;
 502}
 503
 504static void __nft_ct_set_destroy(const struct nft_ctx *ctx, struct nft_ct *priv)
 505{
 506        switch (priv->key) {
 507#ifdef CONFIG_NF_CONNTRACK_LABELS
 508        case NFT_CT_LABELS:
 509                nf_connlabels_put(ctx->net);
 510                break;
 511#endif
 512#ifdef CONFIG_NF_CONNTRACK_ZONES
 513        case NFT_CT_ZONE:
 514                if (--nft_ct_pcpu_template_refcnt == 0)
 515                        nft_ct_tmpl_put_pcpu();
 516#endif
 517        default:
 518                break;
 519        }
 520}
 521
 522static int nft_ct_set_init(const struct nft_ctx *ctx,
 523                           const struct nft_expr *expr,
 524                           const struct nlattr * const tb[])
 525{
 526        struct nft_ct *priv = nft_expr_priv(expr);
 527        unsigned int len;
 528        int err;
 529
 530        priv->dir = IP_CT_DIR_MAX;
 531        priv->key = ntohl(nla_get_be32(tb[NFTA_CT_KEY]));
 532        switch (priv->key) {
 533#ifdef CONFIG_NF_CONNTRACK_MARK
 534        case NFT_CT_MARK:
 535                if (tb[NFTA_CT_DIRECTION])
 536                        return -EINVAL;
 537                len = FIELD_SIZEOF(struct nf_conn, mark);
 538                break;
 539#endif
 540#ifdef CONFIG_NF_CONNTRACK_LABELS
 541        case NFT_CT_LABELS:
 542                if (tb[NFTA_CT_DIRECTION])
 543                        return -EINVAL;
 544                len = NF_CT_LABELS_MAX_SIZE;
 545                err = nf_connlabels_get(ctx->net, (len * BITS_PER_BYTE) - 1);
 546                if (err)
 547                        return err;
 548                break;
 549#endif
 550#ifdef CONFIG_NF_CONNTRACK_ZONES
 551        case NFT_CT_ZONE:
 552                if (!nft_ct_tmpl_alloc_pcpu())
 553                        return -ENOMEM;
 554                nft_ct_pcpu_template_refcnt++;
 555                len = sizeof(u16);
 556                break;
 557#endif
 558#ifdef CONFIG_NF_CONNTRACK_EVENTS
 559        case NFT_CT_EVENTMASK:
 560                if (tb[NFTA_CT_DIRECTION])
 561                        return -EINVAL;
 562                len = sizeof(u32);
 563                break;
 564#endif
 565        default:
 566                return -EOPNOTSUPP;
 567        }
 568
 569        if (tb[NFTA_CT_DIRECTION]) {
 570                priv->dir = nla_get_u8(tb[NFTA_CT_DIRECTION]);
 571                switch (priv->dir) {
 572                case IP_CT_DIR_ORIGINAL:
 573                case IP_CT_DIR_REPLY:
 574                        break;
 575                default:
 576                        err = -EINVAL;
 577                        goto err1;
 578                }
 579        }
 580
 581        priv->sreg = nft_parse_register(tb[NFTA_CT_SREG]);
 582        err = nft_validate_register_load(priv->sreg, len);
 583        if (err < 0)
 584                goto err1;
 585
 586        err = nft_ct_netns_get(ctx->net, ctx->afi->family);
 587        if (err < 0)
 588                goto err1;
 589
 590        return 0;
 591
 592err1:
 593        __nft_ct_set_destroy(ctx, priv);
 594        return err;
 595}
 596
 597static void nft_ct_get_destroy(const struct nft_ctx *ctx,
 598                               const struct nft_expr *expr)
 599{
 600        nf_ct_netns_put(ctx->net, ctx->afi->family);
 601}
 602
 603static void nft_ct_set_destroy(const struct nft_ctx *ctx,
 604                               const struct nft_expr *expr)
 605{
 606        struct nft_ct *priv = nft_expr_priv(expr);
 607
 608        __nft_ct_set_destroy(ctx, priv);
 609        nft_ct_netns_put(ctx->net, ctx->afi->family);
 610}
 611
 612static int nft_ct_get_dump(struct sk_buff *skb, const struct nft_expr *expr)
 613{
 614        const struct nft_ct *priv = nft_expr_priv(expr);
 615
 616        if (nft_dump_register(skb, NFTA_CT_DREG, priv->dreg))
 617                goto nla_put_failure;
 618        if (nla_put_be32(skb, NFTA_CT_KEY, htonl(priv->key)))
 619                goto nla_put_failure;
 620
 621        switch (priv->key) {
 622        case NFT_CT_SRC:
 623        case NFT_CT_DST:
 624        case NFT_CT_PROTO_SRC:
 625        case NFT_CT_PROTO_DST:
 626                if (nla_put_u8(skb, NFTA_CT_DIRECTION, priv->dir))
 627                        goto nla_put_failure;
 628                break;
 629        case NFT_CT_BYTES:
 630        case NFT_CT_PKTS:
 631        case NFT_CT_AVGPKT:
 632        case NFT_CT_ZONE:
 633                if (priv->dir < IP_CT_DIR_MAX &&
 634                    nla_put_u8(skb, NFTA_CT_DIRECTION, priv->dir))
 635                        goto nla_put_failure;
 636                break;
 637        default:
 638                break;
 639        }
 640
 641        return 0;
 642
 643nla_put_failure:
 644        return -1;
 645}
 646
 647static int nft_ct_set_dump(struct sk_buff *skb, const struct nft_expr *expr)
 648{
 649        const struct nft_ct *priv = nft_expr_priv(expr);
 650
 651        if (nft_dump_register(skb, NFTA_CT_SREG, priv->sreg))
 652                goto nla_put_failure;
 653        if (nla_put_be32(skb, NFTA_CT_KEY, htonl(priv->key)))
 654                goto nla_put_failure;
 655
 656        switch (priv->key) {
 657        case NFT_CT_ZONE:
 658                if (priv->dir < IP_CT_DIR_MAX &&
 659                    nla_put_u8(skb, NFTA_CT_DIRECTION, priv->dir))
 660                        goto nla_put_failure;
 661                break;
 662        default:
 663                break;
 664        }
 665
 666        return 0;
 667
 668nla_put_failure:
 669        return -1;
 670}
 671
 672static struct nft_expr_type nft_ct_type;
 673static const struct nft_expr_ops nft_ct_get_ops = {
 674        .type           = &nft_ct_type,
 675        .size           = NFT_EXPR_SIZE(sizeof(struct nft_ct)),
 676        .eval           = nft_ct_get_eval,
 677        .init           = nft_ct_get_init,
 678        .destroy        = nft_ct_get_destroy,
 679        .dump           = nft_ct_get_dump,
 680};
 681
 682static const struct nft_expr_ops nft_ct_set_ops = {
 683        .type           = &nft_ct_type,
 684        .size           = NFT_EXPR_SIZE(sizeof(struct nft_ct)),
 685        .eval           = nft_ct_set_eval,
 686        .init           = nft_ct_set_init,
 687        .destroy        = nft_ct_set_destroy,
 688        .dump           = nft_ct_set_dump,
 689};
 690
 691#ifdef CONFIG_NF_CONNTRACK_ZONES
 692static const struct nft_expr_ops nft_ct_set_zone_ops = {
 693        .type           = &nft_ct_type,
 694        .size           = NFT_EXPR_SIZE(sizeof(struct nft_ct)),
 695        .eval           = nft_ct_set_zone_eval,
 696        .init           = nft_ct_set_init,
 697        .destroy        = nft_ct_set_destroy,
 698        .dump           = nft_ct_set_dump,
 699};
 700#endif
 701
 702static const struct nft_expr_ops *
 703nft_ct_select_ops(const struct nft_ctx *ctx,
 704                    const struct nlattr * const tb[])
 705{
 706        if (tb[NFTA_CT_KEY] == NULL)
 707                return ERR_PTR(-EINVAL);
 708
 709        if (tb[NFTA_CT_DREG] && tb[NFTA_CT_SREG])
 710                return ERR_PTR(-EINVAL);
 711
 712        if (tb[NFTA_CT_DREG])
 713                return &nft_ct_get_ops;
 714
 715        if (tb[NFTA_CT_SREG]) {
 716#ifdef CONFIG_NF_CONNTRACK_ZONES
 717                if (nla_get_be32(tb[NFTA_CT_KEY]) == htonl(NFT_CT_ZONE))
 718                        return &nft_ct_set_zone_ops;
 719#endif
 720                return &nft_ct_set_ops;
 721        }
 722
 723        return ERR_PTR(-EINVAL);
 724}
 725
 726static struct nft_expr_type nft_ct_type __read_mostly = {
 727        .name           = "ct",
 728        .select_ops     = nft_ct_select_ops,
 729        .policy         = nft_ct_policy,
 730        .maxattr        = NFTA_CT_MAX,
 731        .owner          = THIS_MODULE,
 732};
 733
 734static void nft_notrack_eval(const struct nft_expr *expr,
 735                             struct nft_regs *regs,
 736                             const struct nft_pktinfo *pkt)
 737{
 738        struct sk_buff *skb = pkt->skb;
 739        enum ip_conntrack_info ctinfo;
 740        struct nf_conn *ct;
 741
 742        ct = nf_ct_get(pkt->skb, &ctinfo);
 743        /* Previously seen (loopback or untracked)?  Ignore. */
 744        if (ct || ctinfo == IP_CT_UNTRACKED)
 745                return;
 746
 747        nf_ct_set(skb, ct, IP_CT_UNTRACKED);
 748}
 749
 750static struct nft_expr_type nft_notrack_type;
 751static const struct nft_expr_ops nft_notrack_ops = {
 752        .type           = &nft_notrack_type,
 753        .size           = NFT_EXPR_SIZE(0),
 754        .eval           = nft_notrack_eval,
 755};
 756
 757static struct nft_expr_type nft_notrack_type __read_mostly = {
 758        .name           = "notrack",
 759        .ops            = &nft_notrack_ops,
 760        .owner          = THIS_MODULE,
 761};
 762
 763static int nft_ct_helper_obj_init(const struct nft_ctx *ctx,
 764                                  const struct nlattr * const tb[],
 765                                  struct nft_object *obj)
 766{
 767        struct nft_ct_helper_obj *priv = nft_obj_data(obj);
 768        struct nf_conntrack_helper *help4, *help6;
 769        char name[NF_CT_HELPER_NAME_LEN];
 770        int family = ctx->afi->family;
 771
 772        if (!tb[NFTA_CT_HELPER_NAME] || !tb[NFTA_CT_HELPER_L4PROTO])
 773                return -EINVAL;
 774
 775        priv->l4proto = nla_get_u8(tb[NFTA_CT_HELPER_L4PROTO]);
 776        if (!priv->l4proto)
 777                return -ENOENT;
 778
 779        nla_strlcpy(name, tb[NFTA_CT_HELPER_NAME], sizeof(name));
 780
 781        if (tb[NFTA_CT_HELPER_L3PROTO])
 782                family = ntohs(nla_get_be16(tb[NFTA_CT_HELPER_L3PROTO]));
 783
 784        help4 = NULL;
 785        help6 = NULL;
 786
 787        switch (family) {
 788        case NFPROTO_IPV4:
 789                if (ctx->afi->family == NFPROTO_IPV6)
 790                        return -EINVAL;
 791
 792                help4 = nf_conntrack_helper_try_module_get(name, family,
 793                                                           priv->l4proto);
 794                break;
 795        case NFPROTO_IPV6:
 796                if (ctx->afi->family == NFPROTO_IPV4)
 797                        return -EINVAL;
 798
 799                help6 = nf_conntrack_helper_try_module_get(name, family,
 800                                                           priv->l4proto);
 801                break;
 802        case NFPROTO_NETDEV: /* fallthrough */
 803        case NFPROTO_BRIDGE: /* same */
 804        case NFPROTO_INET:
 805                help4 = nf_conntrack_helper_try_module_get(name, NFPROTO_IPV4,
 806                                                           priv->l4proto);
 807                help6 = nf_conntrack_helper_try_module_get(name, NFPROTO_IPV6,
 808                                                           priv->l4proto);
 809                break;
 810        default:
 811                return -EAFNOSUPPORT;
 812        }
 813
 814        /* && is intentional; only error if INET found neither ipv4 or ipv6 */
 815        if (!help4 && !help6)
 816                return -ENOENT;
 817
 818        priv->helper4 = help4;
 819        priv->helper6 = help6;
 820
 821        return 0;
 822}
 823
 824static void nft_ct_helper_obj_destroy(struct nft_object *obj)
 825{
 826        struct nft_ct_helper_obj *priv = nft_obj_data(obj);
 827
 828        if (priv->helper4)
 829                nf_conntrack_helper_put(priv->helper4);
 830        if (priv->helper6)
 831                nf_conntrack_helper_put(priv->helper6);
 832}
 833
 834static void nft_ct_helper_obj_eval(struct nft_object *obj,
 835                                   struct nft_regs *regs,
 836                                   const struct nft_pktinfo *pkt)
 837{
 838        const struct nft_ct_helper_obj *priv = nft_obj_data(obj);
 839        struct nf_conn *ct = (struct nf_conn *)skb_nfct(pkt->skb);
 840        struct nf_conntrack_helper *to_assign = NULL;
 841        struct nf_conn_help *help;
 842
 843        if (!ct ||
 844            nf_ct_is_confirmed(ct) ||
 845            nf_ct_is_template(ct) ||
 846            priv->l4proto != nf_ct_protonum(ct))
 847                return;
 848
 849        switch (nf_ct_l3num(ct)) {
 850        case NFPROTO_IPV4:
 851                to_assign = priv->helper4;
 852                break;
 853        case NFPROTO_IPV6:
 854                to_assign = priv->helper6;
 855                break;
 856        default:
 857                WARN_ON_ONCE(1);
 858                return;
 859        }
 860
 861        if (!to_assign)
 862                return;
 863
 864        if (test_bit(IPS_HELPER_BIT, &ct->status))
 865                return;
 866
 867        help = nf_ct_helper_ext_add(ct, to_assign, GFP_ATOMIC);
 868        if (help) {
 869                rcu_assign_pointer(help->helper, to_assign);
 870                set_bit(IPS_HELPER_BIT, &ct->status);
 871        }
 872}
 873
 874static int nft_ct_helper_obj_dump(struct sk_buff *skb,
 875                                  struct nft_object *obj, bool reset)
 876{
 877        const struct nft_ct_helper_obj *priv = nft_obj_data(obj);
 878        const struct nf_conntrack_helper *helper = priv->helper4;
 879        u16 family;
 880
 881        if (nla_put_string(skb, NFTA_CT_HELPER_NAME, helper->name))
 882                return -1;
 883
 884        if (nla_put_u8(skb, NFTA_CT_HELPER_L4PROTO, priv->l4proto))
 885                return -1;
 886
 887        if (priv->helper4 && priv->helper6)
 888                family = NFPROTO_INET;
 889        else if (priv->helper6)
 890                family = NFPROTO_IPV6;
 891        else
 892                family = NFPROTO_IPV4;
 893
 894        if (nla_put_be16(skb, NFTA_CT_HELPER_L3PROTO, htons(family)))
 895                return -1;
 896
 897        return 0;
 898}
 899
 900static const struct nla_policy nft_ct_helper_policy[NFTA_CT_HELPER_MAX + 1] = {
 901        [NFTA_CT_HELPER_NAME] = { .type = NLA_STRING,
 902                                  .len = NF_CT_HELPER_NAME_LEN - 1 },
 903        [NFTA_CT_HELPER_L3PROTO] = { .type = NLA_U16 },
 904        [NFTA_CT_HELPER_L4PROTO] = { .type = NLA_U8 },
 905};
 906
 907static struct nft_object_type nft_ct_helper_obj __read_mostly = {
 908        .type           = NFT_OBJECT_CT_HELPER,
 909        .size           = sizeof(struct nft_ct_helper_obj),
 910        .maxattr        = NFTA_CT_HELPER_MAX,
 911        .policy         = nft_ct_helper_policy,
 912        .eval           = nft_ct_helper_obj_eval,
 913        .init           = nft_ct_helper_obj_init,
 914        .destroy        = nft_ct_helper_obj_destroy,
 915        .dump           = nft_ct_helper_obj_dump,
 916        .owner          = THIS_MODULE,
 917};
 918
 919static int __init nft_ct_module_init(void)
 920{
 921        int err;
 922
 923        BUILD_BUG_ON(NF_CT_LABELS_MAX_SIZE > NFT_REG_SIZE);
 924
 925        err = nft_register_expr(&nft_ct_type);
 926        if (err < 0)
 927                return err;
 928
 929        err = nft_register_expr(&nft_notrack_type);
 930        if (err < 0)
 931                goto err1;
 932
 933        err = nft_register_obj(&nft_ct_helper_obj);
 934        if (err < 0)
 935                goto err2;
 936
 937        return 0;
 938
 939err2:
 940        nft_unregister_expr(&nft_notrack_type);
 941err1:
 942        nft_unregister_expr(&nft_ct_type);
 943        return err;
 944}
 945
 946static void __exit nft_ct_module_exit(void)
 947{
 948        nft_unregister_obj(&nft_ct_helper_obj);
 949        nft_unregister_expr(&nft_notrack_type);
 950        nft_unregister_expr(&nft_ct_type);
 951}
 952
 953module_init(nft_ct_module_init);
 954module_exit(nft_ct_module_exit);
 955
 956MODULE_LICENSE("GPL");
 957MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
 958MODULE_ALIAS_NFT_EXPR("ct");
 959MODULE_ALIAS_NFT_EXPR("notrack");
 960MODULE_ALIAS_NFT_OBJ(NFT_OBJECT_CT_HELPER);
 961