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        u8                      sreg_addr_min;
  25        u8                      sreg_addr_max;
  26        u8                      sreg_proto_min;
  27        u8                      sreg_proto_max;
  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                if (tb[NFTA_NAT_REG_ADDR_MIN])
 205                        return -EAFNOSUPPORT;
 206                break;
 207        }
 208        priv->family = family;
 209
 210        if (tb[NFTA_NAT_REG_ADDR_MIN]) {
 211                err = nft_parse_register_load(tb[NFTA_NAT_REG_ADDR_MIN],
 212                                              &priv->sreg_addr_min, alen);
 213                if (err < 0)
 214                        return err;
 215
 216                if (tb[NFTA_NAT_REG_ADDR_MAX]) {
 217                        err = nft_parse_register_load(tb[NFTA_NAT_REG_ADDR_MAX],
 218                                                      &priv->sreg_addr_max,
 219                                                      alen);
 220                        if (err < 0)
 221                                return err;
 222                } else {
 223                        priv->sreg_addr_max = priv->sreg_addr_min;
 224                }
 225
 226                priv->flags |= NF_NAT_RANGE_MAP_IPS;
 227        }
 228
 229        plen = sizeof_field(struct nf_nat_range, min_addr.all);
 230        if (tb[NFTA_NAT_REG_PROTO_MIN]) {
 231                err = nft_parse_register_load(tb[NFTA_NAT_REG_PROTO_MIN],
 232                                              &priv->sreg_proto_min, plen);
 233                if (err < 0)
 234                        return err;
 235
 236                if (tb[NFTA_NAT_REG_PROTO_MAX]) {
 237                        err = nft_parse_register_load(tb[NFTA_NAT_REG_PROTO_MAX],
 238                                                      &priv->sreg_proto_max,
 239                                                      plen);
 240                        if (err < 0)
 241                                return err;
 242                } else {
 243                        priv->sreg_proto_max = priv->sreg_proto_min;
 244                }
 245
 246                priv->flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
 247        }
 248
 249        if (tb[NFTA_NAT_FLAGS]) {
 250                priv->flags |= ntohl(nla_get_be32(tb[NFTA_NAT_FLAGS]));
 251                if (priv->flags & ~NF_NAT_RANGE_MASK)
 252                        return -EOPNOTSUPP;
 253        }
 254
 255        return nf_ct_netns_get(ctx->net, family);
 256}
 257
 258static int nft_nat_dump(struct sk_buff *skb, const struct nft_expr *expr)
 259{
 260        const struct nft_nat *priv = nft_expr_priv(expr);
 261
 262        switch (priv->type) {
 263        case NF_NAT_MANIP_SRC:
 264                if (nla_put_be32(skb, NFTA_NAT_TYPE, htonl(NFT_NAT_SNAT)))
 265                        goto nla_put_failure;
 266                break;
 267        case NF_NAT_MANIP_DST:
 268                if (nla_put_be32(skb, NFTA_NAT_TYPE, htonl(NFT_NAT_DNAT)))
 269                        goto nla_put_failure;
 270                break;
 271        }
 272
 273        if (nla_put_be32(skb, NFTA_NAT_FAMILY, htonl(priv->family)))
 274                goto nla_put_failure;
 275
 276        if (priv->sreg_addr_min) {
 277                if (nft_dump_register(skb, NFTA_NAT_REG_ADDR_MIN,
 278                                      priv->sreg_addr_min) ||
 279                    nft_dump_register(skb, NFTA_NAT_REG_ADDR_MAX,
 280                                      priv->sreg_addr_max))
 281                        goto nla_put_failure;
 282        }
 283
 284        if (priv->sreg_proto_min) {
 285                if (nft_dump_register(skb, NFTA_NAT_REG_PROTO_MIN,
 286                                      priv->sreg_proto_min) ||
 287                    nft_dump_register(skb, NFTA_NAT_REG_PROTO_MAX,
 288                                      priv->sreg_proto_max))
 289                        goto nla_put_failure;
 290        }
 291
 292        if (priv->flags != 0) {
 293                if (nla_put_be32(skb, NFTA_NAT_FLAGS, htonl(priv->flags)))
 294                        goto nla_put_failure;
 295        }
 296
 297        return 0;
 298
 299nla_put_failure:
 300        return -1;
 301}
 302
 303static void
 304nft_nat_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr)
 305{
 306        const struct nft_nat *priv = nft_expr_priv(expr);
 307
 308        nf_ct_netns_put(ctx->net, priv->family);
 309}
 310
 311static struct nft_expr_type nft_nat_type;
 312static const struct nft_expr_ops nft_nat_ops = {
 313        .type           = &nft_nat_type,
 314        .size           = NFT_EXPR_SIZE(sizeof(struct nft_nat)),
 315        .eval           = nft_nat_eval,
 316        .init           = nft_nat_init,
 317        .destroy        = nft_nat_destroy,
 318        .dump           = nft_nat_dump,
 319        .validate       = nft_nat_validate,
 320};
 321
 322static struct nft_expr_type nft_nat_type __read_mostly = {
 323        .name           = "nat",
 324        .ops            = &nft_nat_ops,
 325        .policy         = nft_nat_policy,
 326        .maxattr        = NFTA_NAT_MAX,
 327        .owner          = THIS_MODULE,
 328};
 329
 330#ifdef CONFIG_NF_TABLES_INET
 331static void nft_nat_inet_eval(const struct nft_expr *expr,
 332                              struct nft_regs *regs,
 333                              const struct nft_pktinfo *pkt)
 334{
 335        const struct nft_nat *priv = nft_expr_priv(expr);
 336
 337        if (priv->family == nft_pf(pkt))
 338                nft_nat_eval(expr, regs, pkt);
 339}
 340
 341static const struct nft_expr_ops nft_nat_inet_ops = {
 342        .type           = &nft_nat_type,
 343        .size           = NFT_EXPR_SIZE(sizeof(struct nft_nat)),
 344        .eval           = nft_nat_inet_eval,
 345        .init           = nft_nat_init,
 346        .destroy        = nft_nat_destroy,
 347        .dump           = nft_nat_dump,
 348        .validate       = nft_nat_validate,
 349};
 350
 351static struct nft_expr_type nft_inet_nat_type __read_mostly = {
 352        .name           = "nat",
 353        .family         = NFPROTO_INET,
 354        .ops            = &nft_nat_inet_ops,
 355        .policy         = nft_nat_policy,
 356        .maxattr        = NFTA_NAT_MAX,
 357        .owner          = THIS_MODULE,
 358};
 359
 360static int nft_nat_inet_module_init(void)
 361{
 362        return nft_register_expr(&nft_inet_nat_type);
 363}
 364
 365static void nft_nat_inet_module_exit(void)
 366{
 367        nft_unregister_expr(&nft_inet_nat_type);
 368}
 369#else
 370static int nft_nat_inet_module_init(void) { return 0; }
 371static void nft_nat_inet_module_exit(void) { }
 372#endif
 373
 374static int __init nft_nat_module_init(void)
 375{
 376        int ret = nft_nat_inet_module_init();
 377
 378        if (ret)
 379                return ret;
 380
 381        ret = nft_register_expr(&nft_nat_type);
 382        if (ret)
 383                nft_nat_inet_module_exit();
 384
 385        return ret;
 386}
 387
 388static void __exit nft_nat_module_exit(void)
 389{
 390        nft_nat_inet_module_exit();
 391        nft_unregister_expr(&nft_nat_type);
 392}
 393
 394module_init(nft_nat_module_init);
 395module_exit(nft_nat_module_exit);
 396
 397MODULE_LICENSE("GPL");
 398MODULE_AUTHOR("Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>");
 399MODULE_ALIAS_NFT_EXPR("nat");
 400MODULE_DESCRIPTION("Network Address Translation support");
 401