linux/net/netfilter/nft_nat.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
   4 * Copyright (c) 2012 Pablo Neira Ayuso <pablo@netfilter.org>
   5 * Copyright (c) 2012 Intel Corporation
   6 */
   7
   8#include <linux/module.h>
   9#include <linux/init.h>
  10#include <linux/skbuff.h>
  11#include <linux/ip.h>
  12#include <linux/string.h>
  13#include <linux/netlink.h>
  14#include <linux/netfilter.h>
  15#include <linux/netfilter_ipv4.h>
  16#include <linux/netfilter/nfnetlink.h>
  17#include <linux/netfilter/nf_tables.h>
  18#include <net/netfilter/nf_conntrack.h>
  19#include <net/netfilter/nf_nat.h>
  20#include <net/netfilter/nf_tables.h>
  21#include <net/ip.h>
  22
  23struct nft_nat {
  24        enum nft_registers      sreg_addr_min:8;
  25        enum nft_registers      sreg_addr_max:8;
  26        enum nft_registers      sreg_proto_min:8;
  27        enum nft_registers      sreg_proto_max:8;
  28        enum nf_nat_manip_type  type:8;
  29        u8                      family;
  30        u16                     flags;
  31};
  32
  33static void nft_nat_setup_addr(struct nf_nat_range2 *range,
  34                               const struct nft_regs *regs,
  35                               const struct nft_nat *priv)
  36{
  37        switch (priv->family) {
  38        case AF_INET:
  39                range->min_addr.ip = (__force __be32)
  40                                regs->data[priv->sreg_addr_min];
  41                range->max_addr.ip = (__force __be32)
  42                                regs->data[priv->sreg_addr_max];
  43                break;
  44        case AF_INET6:
  45                memcpy(range->min_addr.ip6, &regs->data[priv->sreg_addr_min],
  46                       sizeof(range->min_addr.ip6));
  47                memcpy(range->max_addr.ip6, &regs->data[priv->sreg_addr_max],
  48                       sizeof(range->max_addr.ip6));
  49                break;
  50        }
  51}
  52
  53static void nft_nat_setup_proto(struct nf_nat_range2 *range,
  54                                const struct nft_regs *regs,
  55                                const struct nft_nat *priv)
  56{
  57        range->min_proto.all = (__force __be16)
  58                nft_reg_load16(&regs->data[priv->sreg_proto_min]);
  59        range->max_proto.all = (__force __be16)
  60                nft_reg_load16(&regs->data[priv->sreg_proto_max]);
  61}
  62
  63static void nft_nat_setup_netmap(struct nf_nat_range2 *range,
  64                                 const struct nft_pktinfo *pkt,
  65                                 const struct nft_nat *priv)
  66{
  67        struct sk_buff *skb = pkt->skb;
  68        union nf_inet_addr new_addr;
  69        __be32 netmask;
  70        int i, len = 0;
  71
  72        switch (priv->type) {
  73        case NFT_NAT_SNAT:
  74                if (nft_pf(pkt) == NFPROTO_IPV4) {
  75                        new_addr.ip = ip_hdr(skb)->saddr;
  76                        len = sizeof(struct in_addr);
  77                } else {
  78                        new_addr.in6 = ipv6_hdr(skb)->saddr;
  79                        len = sizeof(struct in6_addr);
  80                }
  81                break;
  82        case NFT_NAT_DNAT:
  83                if (nft_pf(pkt) == NFPROTO_IPV4) {
  84                        new_addr.ip = ip_hdr(skb)->daddr;
  85                        len = sizeof(struct in_addr);
  86                } else {
  87                        new_addr.in6 = ipv6_hdr(skb)->daddr;
  88                        len = sizeof(struct in6_addr);
  89                }
  90                break;
  91        }
  92
  93        for (i = 0; i < len / sizeof(__be32); i++) {
  94                netmask = ~(range->min_addr.ip6[i] ^ range->max_addr.ip6[i]);
  95                new_addr.ip6[i] &= ~netmask;
  96                new_addr.ip6[i] |= range->min_addr.ip6[i] & netmask;
  97        }
  98
  99        range->min_addr = new_addr;
 100        range->max_addr = new_addr;
 101}
 102
 103static void nft_nat_eval(const struct nft_expr *expr,
 104                         struct nft_regs *regs,
 105                         const struct nft_pktinfo *pkt)
 106{
 107        const struct nft_nat *priv = nft_expr_priv(expr);
 108        enum ip_conntrack_info ctinfo;
 109        struct nf_conn *ct = nf_ct_get(pkt->skb, &ctinfo);
 110        struct nf_nat_range2 range;
 111
 112        memset(&range, 0, sizeof(range));
 113
 114        if (priv->sreg_addr_min) {
 115                nft_nat_setup_addr(&range, regs, priv);
 116                if (priv->flags & NF_NAT_RANGE_NETMAP)
 117                        nft_nat_setup_netmap(&range, pkt, priv);
 118        }
 119
 120        if (priv->sreg_proto_min)
 121                nft_nat_setup_proto(&range, regs, priv);
 122
 123        range.flags = priv->flags;
 124
 125        regs->verdict.code = nf_nat_setup_info(ct, &range, priv->type);
 126}
 127
 128static const struct nla_policy nft_nat_policy[NFTA_NAT_MAX + 1] = {
 129        [NFTA_NAT_TYPE]          = { .type = NLA_U32 },
 130        [NFTA_NAT_FAMILY]        = { .type = NLA_U32 },
 131        [NFTA_NAT_REG_ADDR_MIN]  = { .type = NLA_U32 },
 132        [NFTA_NAT_REG_ADDR_MAX]  = { .type = NLA_U32 },
 133        [NFTA_NAT_REG_PROTO_MIN] = { .type = NLA_U32 },
 134        [NFTA_NAT_REG_PROTO_MAX] = { .type = NLA_U32 },
 135        [NFTA_NAT_FLAGS]         = { .type = NLA_U32 },
 136};
 137
 138static int nft_nat_validate(const struct nft_ctx *ctx,
 139                            const struct nft_expr *expr,
 140                            const struct nft_data **data)
 141{
 142        struct nft_nat *priv = nft_expr_priv(expr);
 143        int err;
 144
 145        err = nft_chain_validate_dependency(ctx->chain, NFT_CHAIN_T_NAT);
 146        if (err < 0)
 147                return err;
 148
 149        switch (priv->type) {
 150        case NFT_NAT_SNAT:
 151                err = nft_chain_validate_hooks(ctx->chain,
 152                                               (1 << NF_INET_POST_ROUTING) |
 153                                               (1 << NF_INET_LOCAL_IN));
 154                break;
 155        case NFT_NAT_DNAT:
 156                err = nft_chain_validate_hooks(ctx->chain,
 157                                               (1 << NF_INET_PRE_ROUTING) |
 158                                               (1 << NF_INET_LOCAL_OUT));
 159                break;
 160        }
 161
 162        return err;
 163}
 164
 165static int nft_nat_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
 166                        const struct nlattr * const tb[])
 167{
 168        struct nft_nat *priv = nft_expr_priv(expr);
 169        unsigned int alen, plen;
 170        u32 family;
 171        int err;
 172
 173        if (tb[NFTA_NAT_TYPE] == NULL ||
 174            (tb[NFTA_NAT_REG_ADDR_MIN] == NULL &&
 175             tb[NFTA_NAT_REG_PROTO_MIN] == NULL))
 176                return -EINVAL;
 177
 178        switch (ntohl(nla_get_be32(tb[NFTA_NAT_TYPE]))) {
 179        case NFT_NAT_SNAT:
 180                priv->type = NF_NAT_MANIP_SRC;
 181                break;
 182        case NFT_NAT_DNAT:
 183                priv->type = NF_NAT_MANIP_DST;
 184                break;
 185        default:
 186                return -EOPNOTSUPP;
 187        }
 188
 189        if (tb[NFTA_NAT_FAMILY] == NULL)
 190                return -EINVAL;
 191
 192        family = ntohl(nla_get_be32(tb[NFTA_NAT_FAMILY]));
 193        if (ctx->family != NFPROTO_INET && ctx->family != family)
 194                return -EOPNOTSUPP;
 195
 196        switch (family) {
 197        case NFPROTO_IPV4:
 198                alen = sizeof_field(struct nf_nat_range, min_addr.ip);
 199                break;
 200        case NFPROTO_IPV6:
 201                alen = sizeof_field(struct nf_nat_range, min_addr.ip6);
 202                break;
 203        default:
 204                return -EAFNOSUPPORT;
 205        }
 206        priv->family = family;
 207
 208        if (tb[NFTA_NAT_REG_ADDR_MIN]) {
 209                priv->sreg_addr_min =
 210                        nft_parse_register(tb[NFTA_NAT_REG_ADDR_MIN]);
 211                err = nft_validate_register_load(priv->sreg_addr_min, alen);
 212                if (err < 0)
 213                        return err;
 214
 215                if (tb[NFTA_NAT_REG_ADDR_MAX]) {
 216                        priv->sreg_addr_max =
 217                                nft_parse_register(tb[NFTA_NAT_REG_ADDR_MAX]);
 218
 219                        err = nft_validate_register_load(priv->sreg_addr_max,
 220                                                         alen);
 221                        if (err < 0)
 222                                return err;
 223                } else {
 224                        priv->sreg_addr_max = priv->sreg_addr_min;
 225                }
 226
 227                priv->flags |= NF_NAT_RANGE_MAP_IPS;
 228        }
 229
 230        plen = sizeof_field(struct nf_nat_range, min_addr.all);
 231        if (tb[NFTA_NAT_REG_PROTO_MIN]) {
 232                priv->sreg_proto_min =
 233                        nft_parse_register(tb[NFTA_NAT_REG_PROTO_MIN]);
 234
 235                err = nft_validate_register_load(priv->sreg_proto_min, plen);
 236                if (err < 0)
 237                        return err;
 238
 239                if (tb[NFTA_NAT_REG_PROTO_MAX]) {
 240                        priv->sreg_proto_max =
 241                                nft_parse_register(tb[NFTA_NAT_REG_PROTO_MAX]);
 242
 243                        err = nft_validate_register_load(priv->sreg_proto_max,
 244                                                         plen);
 245                        if (err < 0)
 246                                return err;
 247                } else {
 248                        priv->sreg_proto_max = priv->sreg_proto_min;
 249                }
 250
 251                priv->flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
 252        }
 253
 254        if (tb[NFTA_NAT_FLAGS]) {
 255                priv->flags |= ntohl(nla_get_be32(tb[NFTA_NAT_FLAGS]));
 256                if (priv->flags & ~NF_NAT_RANGE_MASK)
 257                        return -EOPNOTSUPP;
 258        }
 259
 260        return nf_ct_netns_get(ctx->net, family);
 261}
 262
 263static int nft_nat_dump(struct sk_buff *skb, const struct nft_expr *expr)
 264{
 265        const struct nft_nat *priv = nft_expr_priv(expr);
 266
 267        switch (priv->type) {
 268        case NF_NAT_MANIP_SRC:
 269                if (nla_put_be32(skb, NFTA_NAT_TYPE, htonl(NFT_NAT_SNAT)))
 270                        goto nla_put_failure;
 271                break;
 272        case NF_NAT_MANIP_DST:
 273                if (nla_put_be32(skb, NFTA_NAT_TYPE, htonl(NFT_NAT_DNAT)))
 274                        goto nla_put_failure;
 275                break;
 276        }
 277
 278        if (nla_put_be32(skb, NFTA_NAT_FAMILY, htonl(priv->family)))
 279                goto nla_put_failure;
 280
 281        if (priv->sreg_addr_min) {
 282                if (nft_dump_register(skb, NFTA_NAT_REG_ADDR_MIN,
 283                                      priv->sreg_addr_min) ||
 284                    nft_dump_register(skb, NFTA_NAT_REG_ADDR_MAX,
 285                                      priv->sreg_addr_max))
 286                        goto nla_put_failure;
 287        }
 288
 289        if (priv->sreg_proto_min) {
 290                if (nft_dump_register(skb, NFTA_NAT_REG_PROTO_MIN,
 291                                      priv->sreg_proto_min) ||
 292                    nft_dump_register(skb, NFTA_NAT_REG_PROTO_MAX,
 293                                      priv->sreg_proto_max))
 294                        goto nla_put_failure;
 295        }
 296
 297        if (priv->flags != 0) {
 298                if (nla_put_be32(skb, NFTA_NAT_FLAGS, htonl(priv->flags)))
 299                        goto nla_put_failure;
 300        }
 301
 302        return 0;
 303
 304nla_put_failure:
 305        return -1;
 306}
 307
 308static void
 309nft_nat_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr)
 310{
 311        const struct nft_nat *priv = nft_expr_priv(expr);
 312
 313        nf_ct_netns_put(ctx->net, priv->family);
 314}
 315
 316static struct nft_expr_type nft_nat_type;
 317static const struct nft_expr_ops nft_nat_ops = {
 318        .type           = &nft_nat_type,
 319        .size           = NFT_EXPR_SIZE(sizeof(struct nft_nat)),
 320        .eval           = nft_nat_eval,
 321        .init           = nft_nat_init,
 322        .destroy        = nft_nat_destroy,
 323        .dump           = nft_nat_dump,
 324        .validate       = nft_nat_validate,
 325};
 326
 327static struct nft_expr_type nft_nat_type __read_mostly = {
 328        .name           = "nat",
 329        .ops            = &nft_nat_ops,
 330        .policy         = nft_nat_policy,
 331        .maxattr        = NFTA_NAT_MAX,
 332        .owner          = THIS_MODULE,
 333};
 334
 335#ifdef CONFIG_NF_TABLES_INET
 336static void nft_nat_inet_eval(const struct nft_expr *expr,
 337                              struct nft_regs *regs,
 338                              const struct nft_pktinfo *pkt)
 339{
 340        const struct nft_nat *priv = nft_expr_priv(expr);
 341
 342        if (priv->family == nft_pf(pkt))
 343                nft_nat_eval(expr, regs, pkt);
 344}
 345
 346static const struct nft_expr_ops nft_nat_inet_ops = {
 347        .type           = &nft_nat_type,
 348        .size           = NFT_EXPR_SIZE(sizeof(struct nft_nat)),
 349        .eval           = nft_nat_inet_eval,
 350        .init           = nft_nat_init,
 351        .destroy        = nft_nat_destroy,
 352        .dump           = nft_nat_dump,
 353        .validate       = nft_nat_validate,
 354};
 355
 356static struct nft_expr_type nft_inet_nat_type __read_mostly = {
 357        .name           = "nat",
 358        .family         = NFPROTO_INET,
 359        .ops            = &nft_nat_inet_ops,
 360        .policy         = nft_nat_policy,
 361        .maxattr        = NFTA_NAT_MAX,
 362        .owner          = THIS_MODULE,
 363};
 364
 365static int nft_nat_inet_module_init(void)
 366{
 367        return nft_register_expr(&nft_inet_nat_type);
 368}
 369
 370static void nft_nat_inet_module_exit(void)
 371{
 372        nft_unregister_expr(&nft_inet_nat_type);
 373}
 374#else
 375static int nft_nat_inet_module_init(void) { return 0; }
 376static void nft_nat_inet_module_exit(void) { }
 377#endif
 378
 379static int __init nft_nat_module_init(void)
 380{
 381        int ret = nft_nat_inet_module_init();
 382
 383        if (ret)
 384                return ret;
 385
 386        ret = nft_register_expr(&nft_nat_type);
 387        if (ret)
 388                nft_nat_inet_module_exit();
 389
 390        return ret;
 391}
 392
 393static void __exit nft_nat_module_exit(void)
 394{
 395        nft_nat_inet_module_exit();
 396        nft_unregister_expr(&nft_nat_type);
 397}
 398
 399module_init(nft_nat_module_init);
 400module_exit(nft_nat_module_exit);
 401
 402MODULE_LICENSE("GPL");
 403MODULE_AUTHOR("Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>");
 404MODULE_ALIAS_NFT_EXPR("nat");
 405MODULE_DESCRIPTION("Network Address Translation support");
 406