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        enum nft_registers      sreg_proto_min:8;
  19        enum nft_registers      sreg_proto_max:8;
  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 = FIELD_SIZEOF(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                priv->sreg_proto_min =
  58                        nft_parse_register(tb[NFTA_MASQ_REG_PROTO_MIN]);
  59
  60                err = nft_validate_register_load(priv->sreg_proto_min, plen);
  61                if (err < 0)
  62                        return err;
  63
  64                if (tb[NFTA_MASQ_REG_PROTO_MAX]) {
  65                        priv->sreg_proto_max =
  66                                nft_parse_register(tb[NFTA_MASQ_REG_PROTO_MAX]);
  67
  68                        err = nft_validate_register_load(priv->sreg_proto_max,
  69                                                         plen);
  70                        if (err < 0)
  71                                return err;
  72                } else {
  73                        priv->sreg_proto_max = priv->sreg_proto_min;
  74                }
  75        }
  76
  77        return nf_ct_netns_get(ctx->net, ctx->family);
  78}
  79
  80static int nft_masq_dump(struct sk_buff *skb, const struct nft_expr *expr)
  81{
  82        const struct nft_masq *priv = nft_expr_priv(expr);
  83
  84        if (priv->flags != 0 &&
  85            nla_put_be32(skb, NFTA_MASQ_FLAGS, htonl(priv->flags)))
  86                goto nla_put_failure;
  87
  88        if (priv->sreg_proto_min) {
  89                if (nft_dump_register(skb, NFTA_MASQ_REG_PROTO_MIN,
  90                                      priv->sreg_proto_min) ||
  91                    nft_dump_register(skb, NFTA_MASQ_REG_PROTO_MAX,
  92                                      priv->sreg_proto_max))
  93                        goto nla_put_failure;
  94        }
  95
  96        return 0;
  97
  98nla_put_failure:
  99        return -1;
 100}
 101
 102static void nft_masq_ipv4_eval(const struct nft_expr *expr,
 103                               struct nft_regs *regs,
 104                               const struct nft_pktinfo *pkt)
 105{
 106        struct nft_masq *priv = nft_expr_priv(expr);
 107        struct nf_nat_range2 range;
 108
 109        memset(&range, 0, sizeof(range));
 110        range.flags = priv->flags;
 111        if (priv->sreg_proto_min) {
 112                range.min_proto.all = (__force __be16)nft_reg_load16(
 113                        &regs->data[priv->sreg_proto_min]);
 114                range.max_proto.all = (__force __be16)nft_reg_load16(
 115                        &regs->data[priv->sreg_proto_max]);
 116        }
 117        regs->verdict.code = nf_nat_masquerade_ipv4(pkt->skb, nft_hook(pkt),
 118                                                    &range, nft_out(pkt));
 119}
 120
 121static void
 122nft_masq_ipv4_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr)
 123{
 124        nf_ct_netns_put(ctx->net, NFPROTO_IPV4);
 125}
 126
 127static struct nft_expr_type nft_masq_ipv4_type;
 128static const struct nft_expr_ops nft_masq_ipv4_ops = {
 129        .type           = &nft_masq_ipv4_type,
 130        .size           = NFT_EXPR_SIZE(sizeof(struct nft_masq)),
 131        .eval           = nft_masq_ipv4_eval,
 132        .init           = nft_masq_init,
 133        .destroy        = nft_masq_ipv4_destroy,
 134        .dump           = nft_masq_dump,
 135        .validate       = nft_masq_validate,
 136};
 137
 138static struct nft_expr_type nft_masq_ipv4_type __read_mostly = {
 139        .family         = NFPROTO_IPV4,
 140        .name           = "masq",
 141        .ops            = &nft_masq_ipv4_ops,
 142        .policy         = nft_masq_policy,
 143        .maxattr        = NFTA_MASQ_MAX,
 144        .owner          = THIS_MODULE,
 145};
 146
 147#ifdef CONFIG_NF_TABLES_IPV6
 148static void nft_masq_ipv6_eval(const struct nft_expr *expr,
 149                               struct nft_regs *regs,
 150                               const struct nft_pktinfo *pkt)
 151{
 152        struct nft_masq *priv = nft_expr_priv(expr);
 153        struct nf_nat_range2 range;
 154
 155        memset(&range, 0, sizeof(range));
 156        range.flags = priv->flags;
 157        if (priv->sreg_proto_min) {
 158                range.min_proto.all = (__force __be16)nft_reg_load16(
 159                        &regs->data[priv->sreg_proto_min]);
 160                range.max_proto.all = (__force __be16)nft_reg_load16(
 161                        &regs->data[priv->sreg_proto_max]);
 162        }
 163        regs->verdict.code = nf_nat_masquerade_ipv6(pkt->skb, &range,
 164                                                    nft_out(pkt));
 165}
 166
 167static void
 168nft_masq_ipv6_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr)
 169{
 170        nf_ct_netns_put(ctx->net, NFPROTO_IPV6);
 171}
 172
 173static struct nft_expr_type nft_masq_ipv6_type;
 174static const struct nft_expr_ops nft_masq_ipv6_ops = {
 175        .type           = &nft_masq_ipv6_type,
 176        .size           = NFT_EXPR_SIZE(sizeof(struct nft_masq)),
 177        .eval           = nft_masq_ipv6_eval,
 178        .init           = nft_masq_init,
 179        .destroy        = nft_masq_ipv6_destroy,
 180        .dump           = nft_masq_dump,
 181        .validate       = nft_masq_validate,
 182};
 183
 184static struct nft_expr_type nft_masq_ipv6_type __read_mostly = {
 185        .family         = NFPROTO_IPV6,
 186        .name           = "masq",
 187        .ops            = &nft_masq_ipv6_ops,
 188        .policy         = nft_masq_policy,
 189        .maxattr        = NFTA_MASQ_MAX,
 190        .owner          = THIS_MODULE,
 191};
 192
 193static int __init nft_masq_module_init_ipv6(void)
 194{
 195        return nft_register_expr(&nft_masq_ipv6_type);
 196}
 197
 198static void nft_masq_module_exit_ipv6(void)
 199{
 200        nft_unregister_expr(&nft_masq_ipv6_type);
 201}
 202#else
 203static inline int nft_masq_module_init_ipv6(void) { return 0; }
 204static inline void nft_masq_module_exit_ipv6(void) {}
 205#endif
 206
 207#ifdef CONFIG_NF_TABLES_INET
 208static void nft_masq_inet_eval(const struct nft_expr *expr,
 209                               struct nft_regs *regs,
 210                               const struct nft_pktinfo *pkt)
 211{
 212        switch (nft_pf(pkt)) {
 213        case NFPROTO_IPV4:
 214                return nft_masq_ipv4_eval(expr, regs, pkt);
 215        case NFPROTO_IPV6:
 216                return nft_masq_ipv6_eval(expr, regs, pkt);
 217        }
 218
 219        WARN_ON_ONCE(1);
 220}
 221
 222static void
 223nft_masq_inet_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr)
 224{
 225        nf_ct_netns_put(ctx->net, NFPROTO_INET);
 226}
 227
 228static struct nft_expr_type nft_masq_inet_type;
 229static const struct nft_expr_ops nft_masq_inet_ops = {
 230        .type           = &nft_masq_inet_type,
 231        .size           = NFT_EXPR_SIZE(sizeof(struct nft_masq)),
 232        .eval           = nft_masq_inet_eval,
 233        .init           = nft_masq_init,
 234        .destroy        = nft_masq_inet_destroy,
 235        .dump           = nft_masq_dump,
 236        .validate       = nft_masq_validate,
 237};
 238
 239static struct nft_expr_type nft_masq_inet_type __read_mostly = {
 240        .family         = NFPROTO_INET,
 241        .name           = "masq",
 242        .ops            = &nft_masq_inet_ops,
 243        .policy         = nft_masq_policy,
 244        .maxattr        = NFTA_MASQ_MAX,
 245        .owner          = THIS_MODULE,
 246};
 247
 248static int __init nft_masq_module_init_inet(void)
 249{
 250        return nft_register_expr(&nft_masq_inet_type);
 251}
 252
 253static void nft_masq_module_exit_inet(void)
 254{
 255        nft_unregister_expr(&nft_masq_inet_type);
 256}
 257#else
 258static inline int nft_masq_module_init_inet(void) { return 0; }
 259static inline void nft_masq_module_exit_inet(void) {}
 260#endif
 261
 262static int __init nft_masq_module_init(void)
 263{
 264        int ret;
 265
 266        ret = nft_masq_module_init_ipv6();
 267        if (ret < 0)
 268                return ret;
 269
 270        ret = nft_masq_module_init_inet();
 271        if (ret < 0) {
 272                nft_masq_module_exit_ipv6();
 273                return ret;
 274        }
 275
 276        ret = nft_register_expr(&nft_masq_ipv4_type);
 277        if (ret < 0) {
 278                nft_masq_module_exit_inet();
 279                nft_masq_module_exit_ipv6();
 280                return ret;
 281        }
 282
 283        ret = nf_nat_masquerade_inet_register_notifiers();
 284        if (ret < 0) {
 285                nft_masq_module_exit_ipv6();
 286                nft_masq_module_exit_inet();
 287                nft_unregister_expr(&nft_masq_ipv4_type);
 288                return ret;
 289        }
 290
 291        return ret;
 292}
 293
 294static void __exit nft_masq_module_exit(void)
 295{
 296        nft_masq_module_exit_ipv6();
 297        nft_masq_module_exit_inet();
 298        nft_unregister_expr(&nft_masq_ipv4_type);
 299        nf_nat_masquerade_inet_unregister_notifiers();
 300}
 301
 302module_init(nft_masq_module_init);
 303module_exit(nft_masq_module_exit);
 304
 305MODULE_LICENSE("GPL");
 306MODULE_AUTHOR("Arturo Borrero Gonzalez <arturo@debian.org>");
 307MODULE_ALIAS_NFT_EXPR("masq");
 308