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