linux/net/ipv6/netfilter/ip6table_nat.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (c) 2011 Patrick McHardy <kaber@trash.net>
   4 *
   5 * Based on Rusty Russell's IPv4 NAT code. Development of IPv6 NAT
   6 * funded by Astaro.
   7 */
   8
   9#include <linux/module.h>
  10#include <linux/netfilter.h>
  11#include <linux/netfilter_ipv6.h>
  12#include <linux/netfilter_ipv6/ip6_tables.h>
  13#include <linux/ipv6.h>
  14#include <net/ipv6.h>
  15
  16#include <net/netfilter/nf_nat.h>
  17
  18static int __net_init ip6table_nat_table_init(struct net *net);
  19
  20static const struct xt_table nf_nat_ipv6_table = {
  21        .name           = "nat",
  22        .valid_hooks    = (1 << NF_INET_PRE_ROUTING) |
  23                          (1 << NF_INET_POST_ROUTING) |
  24                          (1 << NF_INET_LOCAL_OUT) |
  25                          (1 << NF_INET_LOCAL_IN),
  26        .me             = THIS_MODULE,
  27        .af             = NFPROTO_IPV6,
  28        .table_init     = ip6table_nat_table_init,
  29};
  30
  31static unsigned int ip6table_nat_do_chain(void *priv,
  32                                          struct sk_buff *skb,
  33                                          const struct nf_hook_state *state)
  34{
  35        return ip6t_do_table(skb, state, state->net->ipv6.ip6table_nat);
  36}
  37
  38static const struct nf_hook_ops nf_nat_ipv6_ops[] = {
  39        {
  40                .hook           = ip6table_nat_do_chain,
  41                .pf             = NFPROTO_IPV6,
  42                .hooknum        = NF_INET_PRE_ROUTING,
  43                .priority       = NF_IP6_PRI_NAT_DST,
  44        },
  45        {
  46                .hook           = ip6table_nat_do_chain,
  47                .pf             = NFPROTO_IPV6,
  48                .hooknum        = NF_INET_POST_ROUTING,
  49                .priority       = NF_IP6_PRI_NAT_SRC,
  50        },
  51        {
  52                .hook           = ip6table_nat_do_chain,
  53                .pf             = NFPROTO_IPV6,
  54                .hooknum        = NF_INET_LOCAL_OUT,
  55                .priority       = NF_IP6_PRI_NAT_DST,
  56        },
  57        {
  58                .hook           = ip6table_nat_do_chain,
  59                .pf             = NFPROTO_IPV6,
  60                .hooknum        = NF_INET_LOCAL_IN,
  61                .priority       = NF_IP6_PRI_NAT_SRC,
  62        },
  63};
  64
  65static int ip6t_nat_register_lookups(struct net *net)
  66{
  67        int i, ret;
  68
  69        for (i = 0; i < ARRAY_SIZE(nf_nat_ipv6_ops); i++) {
  70                ret = nf_nat_ipv6_register_fn(net, &nf_nat_ipv6_ops[i]);
  71                if (ret) {
  72                        while (i)
  73                                nf_nat_ipv6_unregister_fn(net, &nf_nat_ipv6_ops[--i]);
  74
  75                        return ret;
  76                }
  77        }
  78
  79        return 0;
  80}
  81
  82static void ip6t_nat_unregister_lookups(struct net *net)
  83{
  84        int i;
  85
  86        for (i = 0; i < ARRAY_SIZE(nf_nat_ipv6_ops); i++)
  87                nf_nat_ipv6_unregister_fn(net, &nf_nat_ipv6_ops[i]);
  88}
  89
  90static int __net_init ip6table_nat_table_init(struct net *net)
  91{
  92        struct ip6t_replace *repl;
  93        int ret;
  94
  95        if (net->ipv6.ip6table_nat)
  96                return 0;
  97
  98        repl = ip6t_alloc_initial_table(&nf_nat_ipv6_table);
  99        if (repl == NULL)
 100                return -ENOMEM;
 101        ret = ip6t_register_table(net, &nf_nat_ipv6_table, repl,
 102                                  NULL, &net->ipv6.ip6table_nat);
 103        if (ret < 0) {
 104                kfree(repl);
 105                return ret;
 106        }
 107
 108        ret = ip6t_nat_register_lookups(net);
 109        if (ret < 0) {
 110                ip6t_unregister_table(net, net->ipv6.ip6table_nat, NULL);
 111                net->ipv6.ip6table_nat = NULL;
 112        }
 113        kfree(repl);
 114        return ret;
 115}
 116
 117static void __net_exit ip6table_nat_net_exit(struct net *net)
 118{
 119        if (!net->ipv6.ip6table_nat)
 120                return;
 121        ip6t_nat_unregister_lookups(net);
 122        ip6t_unregister_table(net, net->ipv6.ip6table_nat, NULL);
 123        net->ipv6.ip6table_nat = NULL;
 124}
 125
 126static struct pernet_operations ip6table_nat_net_ops = {
 127        .exit   = ip6table_nat_net_exit,
 128};
 129
 130static int __init ip6table_nat_init(void)
 131{
 132        int ret = register_pernet_subsys(&ip6table_nat_net_ops);
 133
 134        if (ret)
 135                return ret;
 136
 137        ret = ip6table_nat_table_init(&init_net);
 138        if (ret)
 139                unregister_pernet_subsys(&ip6table_nat_net_ops);
 140        return ret;
 141}
 142
 143static void __exit ip6table_nat_exit(void)
 144{
 145        unregister_pernet_subsys(&ip6table_nat_net_ops);
 146}
 147
 148module_init(ip6table_nat_init);
 149module_exit(ip6table_nat_exit);
 150
 151MODULE_LICENSE("GPL");
 152