linux/net/netfilter/nft_masq.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (c) 2014 Arturo Borrero Gonzalez <arturo@debian.org>
   4 */
   5
   6#include <linux/kernel.h>
   7#include <linux/init.h>
   8#include <linux/module.h>
   9#include <linux/netlink.h>
  10#include <linux/netfilter.h>
  11#include <linux/netfilter/nf_tables.h>
  12#include <net/netfilter/nf_tables.h>
  13#include <net/netfilter/nf_nat.h>
  14#include <net/netfilter/nf_nat_masquerade.h>
  15
  16struct nft_masq {
  17        u32                     flags;
  18        u8                      sreg_proto_min;
  19        u8                      sreg_proto_max;
  20};
  21
  22static const struct nla_policy nft_masq_policy[NFTA_MASQ_MAX + 1] = {
  23        [NFTA_MASQ_FLAGS]               = { .type = NLA_U32 },
  24        [NFTA_MASQ_REG_PROTO_MIN]       = { .type = NLA_U32 },
  25        [NFTA_MASQ_REG_PROTO_MAX]       = { .type = NLA_U32 },
  26};
  27
  28static int nft_masq_validate(const struct nft_ctx *ctx,
  29                             const struct nft_expr *expr,
  30                             const struct nft_data **data)
  31{
  32        int err;
  33
  34        err = nft_chain_validate_dependency(ctx->chain, NFT_CHAIN_T_NAT);
  35        if (err < 0)
  36                return err;
  37
  38        return nft_chain_validate_hooks(ctx->chain,
  39                                        (1 << NF_INET_POST_ROUTING));
  40}
  41
  42static int nft_masq_init(const struct nft_ctx *ctx,
  43                         const struct nft_expr *expr,
  44                         const struct nlattr * const tb[])
  45{
  46        u32 plen = sizeof_field(struct nf_nat_range, min_addr.all);
  47        struct nft_masq *priv = nft_expr_priv(expr);
  48        int err;
  49
  50        if (tb[NFTA_MASQ_FLAGS]) {
  51                priv->flags = ntohl(nla_get_be32(tb[NFTA_MASQ_FLAGS]));
  52                if (priv->flags & ~NF_NAT_RANGE_MASK)
  53                        return -EINVAL;
  54        }
  55
  56        if (tb[NFTA_MASQ_REG_PROTO_MIN]) {
  57                err = nft_parse_register_load(tb[NFTA_MASQ_REG_PROTO_MIN],
  58                                              &priv->sreg_proto_min, plen);
  59                if (err < 0)
  60                        return err;
  61
  62                if (tb[NFTA_MASQ_REG_PROTO_MAX]) {
  63                        err = nft_parse_register_load(tb[NFTA_MASQ_REG_PROTO_MAX],
  64                                                      &priv->sreg_proto_max,
  65                                                      plen);
  66                        if (err < 0)
  67                                return err;
  68                } else {
  69                        priv->sreg_proto_max = priv->sreg_proto_min;
  70                }
  71        }
  72
  73        return nf_ct_netns_get(ctx->net, ctx->family);
  74}
  75
  76static int nft_masq_dump(struct sk_buff *skb, const struct nft_expr *expr)
  77{
  78        const struct nft_masq *priv = nft_expr_priv(expr);
  79
  80        if (priv->flags != 0 &&
  81            nla_put_be32(skb, NFTA_MASQ_FLAGS, htonl(priv->flags)))
  82                goto nla_put_failure;
  83
  84        if (priv->sreg_proto_min) {
  85                if (nft_dump_register(skb, NFTA_MASQ_REG_PROTO_MIN,
  86                                      priv->sreg_proto_min) ||
  87                    nft_dump_register(skb, NFTA_MASQ_REG_PROTO_MAX,
  88                                      priv->sreg_proto_max))
  89                        goto nla_put_failure;
  90        }
  91
  92        return 0;
  93
  94nla_put_failure:
  95        return -1;
  96}
  97
  98static void nft_masq_ipv4_eval(const struct nft_expr *expr,
  99                               struct nft_regs *regs,
 100                               const struct nft_pktinfo *pkt)
 101{
 102        struct nft_masq *priv = nft_expr_priv(expr);
 103        struct nf_nat_range2 range;
 104
 105        memset(&range, 0, sizeof(range));
 106        range.flags = priv->flags;
 107        if (priv->sreg_proto_min) {
 108                range.min_proto.all = (__force __be16)nft_reg_load16(
 109                        &regs->data[priv->sreg_proto_min]);
 110                range.max_proto.all = (__force __be16)nft_reg_load16(
 111                        &regs->data[priv->sreg_proto_max]);
 112        }
 113        regs->verdict.code = nf_nat_masquerade_ipv4(pkt->skb, nft_hook(pkt),
 114                                                    &range, nft_out(pkt));
 115}
 116
 117static void
 118nft_masq_ipv4_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr)
 119{
 120        nf_ct_netns_put(ctx->net, NFPROTO_IPV4);
 121}
 122
 123static struct nft_expr_type nft_masq_ipv4_type;
 124static const struct nft_expr_ops nft_masq_ipv4_ops = {
 125        .type           = &nft_masq_ipv4_type,
 126        .size           = NFT_EXPR_SIZE(sizeof(struct nft_masq)),
 127        .eval           = nft_masq_ipv4_eval,
 128        .init           = nft_masq_init,
 129        .destroy        = nft_masq_ipv4_destroy,
 130        .dump           = nft_masq_dump,
 131        .validate       = nft_masq_validate,
 132};
 133
 134static struct nft_expr_type nft_masq_ipv4_type __read_mostly = {
 135        .family         = NFPROTO_IPV4,
 136        .name           = "masq",
 137        .ops            = &nft_masq_ipv4_ops,
 138        .policy         = nft_masq_policy,
 139        .maxattr        = NFTA_MASQ_MAX,
 140        .owner          = THIS_MODULE,
 141};
 142
 143#ifdef CONFIG_NF_TABLES_IPV6
 144static void nft_masq_ipv6_eval(const struct nft_expr *expr,
 145                               struct nft_regs *regs,
 146                               const struct nft_pktinfo *pkt)
 147{
 148        struct nft_masq *priv = nft_expr_priv(expr);
 149        struct nf_nat_range2 range;
 150
 151        memset(&range, 0, sizeof(range));
 152        range.flags = priv->flags;
 153        if (priv->sreg_proto_min) {
 154                range.min_proto.all = (__force __be16)nft_reg_load16(
 155                        &regs->data[priv->sreg_proto_min]);
 156                range.max_proto.all = (__force __be16)nft_reg_load16(
 157                        &regs->data[priv->sreg_proto_max]);
 158        }
 159        regs->verdict.code = nf_nat_masquerade_ipv6(pkt->skb, &range,
 160                                                    nft_out(pkt));
 161}
 162
 163static void
 164nft_masq_ipv6_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr)
 165{
 166        nf_ct_netns_put(ctx->net, NFPROTO_IPV6);
 167}
 168
 169static struct nft_expr_type nft_masq_ipv6_type;
 170static const struct nft_expr_ops nft_masq_ipv6_ops = {
 171        .type           = &nft_masq_ipv6_type,
 172        .size           = NFT_EXPR_SIZE(sizeof(struct nft_masq)),
 173        .eval           = nft_masq_ipv6_eval,
 174        .init           = nft_masq_init,
 175        .destroy        = nft_masq_ipv6_destroy,
 176        .dump           = nft_masq_dump,
 177        .validate       = nft_masq_validate,
 178};
 179
 180static struct nft_expr_type nft_masq_ipv6_type __read_mostly = {
 181        .family         = NFPROTO_IPV6,
 182        .name           = "masq",
 183        .ops            = &nft_masq_ipv6_ops,
 184        .policy         = nft_masq_policy,
 185        .maxattr        = NFTA_MASQ_MAX,
 186        .owner          = THIS_MODULE,
 187};
 188
 189static int __init nft_masq_module_init_ipv6(void)
 190{
 191        return nft_register_expr(&nft_masq_ipv6_type);
 192}
 193
 194static void nft_masq_module_exit_ipv6(void)
 195{
 196        nft_unregister_expr(&nft_masq_ipv6_type);
 197}
 198#else
 199static inline int nft_masq_module_init_ipv6(void) { return 0; }
 200static inline void nft_masq_module_exit_ipv6(void) {}
 201#endif
 202
 203#ifdef CONFIG_NF_TABLES_INET
 204static void nft_masq_inet_eval(const struct nft_expr *expr,
 205                               struct nft_regs *regs,
 206                               const struct nft_pktinfo *pkt)
 207{
 208        switch (nft_pf(pkt)) {
 209        case NFPROTO_IPV4:
 210                return nft_masq_ipv4_eval(expr, regs, pkt);
 211        case NFPROTO_IPV6:
 212                return nft_masq_ipv6_eval(expr, regs, pkt);
 213        }
 214
 215        WARN_ON_ONCE(1);
 216}
 217
 218static void
 219nft_masq_inet_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr)
 220{
 221        nf_ct_netns_put(ctx->net, NFPROTO_INET);
 222}
 223
 224static struct nft_expr_type nft_masq_inet_type;
 225static const struct nft_expr_ops nft_masq_inet_ops = {
 226        .type           = &nft_masq_inet_type,
 227        .size           = NFT_EXPR_SIZE(sizeof(struct nft_masq)),
 228        .eval           = nft_masq_inet_eval,
 229        .init           = nft_masq_init,
 230        .destroy        = nft_masq_inet_destroy,
 231        .dump           = nft_masq_dump,
 232        .validate       = nft_masq_validate,
 233};
 234
 235static struct nft_expr_type nft_masq_inet_type __read_mostly = {
 236        .family         = NFPROTO_INET,
 237        .name           = "masq",
 238        .ops            = &nft_masq_inet_ops,
 239        .policy         = nft_masq_policy,
 240        .maxattr        = NFTA_MASQ_MAX,
 241        .owner          = THIS_MODULE,
 242};
 243
 244static int __init nft_masq_module_init_inet(void)
 245{
 246        return nft_register_expr(&nft_masq_inet_type);
 247}
 248
 249static void nft_masq_module_exit_inet(void)
 250{
 251        nft_unregister_expr(&nft_masq_inet_type);
 252}
 253#else
 254static inline int nft_masq_module_init_inet(void) { return 0; }
 255static inline void nft_masq_module_exit_inet(void) {}
 256#endif
 257
 258static int __init nft_masq_module_init(void)
 259{
 260        int ret;
 261
 262        ret = nft_masq_module_init_ipv6();
 263        if (ret < 0)
 264                return ret;
 265
 266        ret = nft_masq_module_init_inet();
 267        if (ret < 0) {
 268                nft_masq_module_exit_ipv6();
 269                return ret;
 270        }
 271
 272        ret = nft_register_expr(&nft_masq_ipv4_type);
 273        if (ret < 0) {
 274                nft_masq_module_exit_inet();
 275                nft_masq_module_exit_ipv6();
 276                return ret;
 277        }
 278
 279        ret = nf_nat_masquerade_inet_register_notifiers();
 280        if (ret < 0) {
 281                nft_masq_module_exit_ipv6();
 282                nft_masq_module_exit_inet();
 283                nft_unregister_expr(&nft_masq_ipv4_type);
 284                return ret;
 285        }
 286
 287        return ret;
 288}
 289
 290static void __exit nft_masq_module_exit(void)
 291{
 292        nft_masq_module_exit_ipv6();
 293        nft_masq_module_exit_inet();
 294        nft_unregister_expr(&nft_masq_ipv4_type);
 295        nf_nat_masquerade_inet_unregister_notifiers();
 296}
 297
 298module_init(nft_masq_module_init);
 299module_exit(nft_masq_module_exit);
 300
 301MODULE_LICENSE("GPL");
 302MODULE_AUTHOR("Arturo Borrero Gonzalez <arturo@debian.org>");
 303MODULE_ALIAS_NFT_EXPR("masq");
 304MODULE_DESCRIPTION("Netfilter nftables masquerade expression support");
 305