Merge tag 'spi-v3.19' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi
[cascardo/linux.git] / net / ipv6 / netfilter / ip6table_nat.c
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
23 static const struct xt_table nf_nat_ipv6_table = {
24         .name           = "nat",
25         .valid_hooks    = (1 << NF_INET_PRE_ROUTING) |
26                           (1 << NF_INET_POST_ROUTING) |
27                           (1 << NF_INET_LOCAL_OUT) |
28                           (1 << NF_INET_LOCAL_IN),
29         .me             = THIS_MODULE,
30         .af             = NFPROTO_IPV6,
31 };
32
33 static unsigned int ip6table_nat_do_chain(const struct nf_hook_ops *ops,
34                                           struct sk_buff *skb,
35                                           const struct net_device *in,
36                                           const struct net_device *out,
37                                           struct nf_conn *ct)
38 {
39         struct net *net = nf_ct_net(ct);
40
41         return ip6t_do_table(skb, ops->hooknum, in, out, net->ipv6.ip6table_nat);
42 }
43
44 static unsigned int ip6table_nat_fn(const struct nf_hook_ops *ops,
45                                     struct sk_buff *skb,
46                                     const struct net_device *in,
47                                     const struct net_device *out,
48                                     int (*okfn)(struct sk_buff *))
49 {
50         return nf_nat_ipv6_fn(ops, skb, in, out, ip6table_nat_do_chain);
51 }
52
53 static unsigned int ip6table_nat_in(const struct nf_hook_ops *ops,
54                                     struct sk_buff *skb,
55                                     const struct net_device *in,
56                                     const struct net_device *out,
57                                     int (*okfn)(struct sk_buff *))
58 {
59         return nf_nat_ipv6_in(ops, skb, in, out, ip6table_nat_do_chain);
60 }
61
62 static unsigned int ip6table_nat_out(const struct nf_hook_ops *ops,
63                                      struct sk_buff *skb,
64                                      const struct net_device *in,
65                                      const struct net_device *out,
66                                      int (*okfn)(struct sk_buff *))
67 {
68         return nf_nat_ipv6_out(ops, skb, in, out, ip6table_nat_do_chain);
69 }
70
71 static unsigned int ip6table_nat_local_fn(const struct nf_hook_ops *ops,
72                                           struct sk_buff *skb,
73                                           const struct net_device *in,
74                                           const struct net_device *out,
75                                           int (*okfn)(struct sk_buff *))
76 {
77         return nf_nat_ipv6_local_fn(ops, skb, in, out, ip6table_nat_do_chain);
78 }
79
80 static struct nf_hook_ops nf_nat_ipv6_ops[] __read_mostly = {
81         /* Before packet filtering, change destination */
82         {
83                 .hook           = ip6table_nat_in,
84                 .owner          = THIS_MODULE,
85                 .pf             = NFPROTO_IPV6,
86                 .hooknum        = NF_INET_PRE_ROUTING,
87                 .priority       = NF_IP6_PRI_NAT_DST,
88         },
89         /* After packet filtering, change source */
90         {
91                 .hook           = ip6table_nat_out,
92                 .owner          = THIS_MODULE,
93                 .pf             = NFPROTO_IPV6,
94                 .hooknum        = NF_INET_POST_ROUTING,
95                 .priority       = NF_IP6_PRI_NAT_SRC,
96         },
97         /* Before packet filtering, change destination */
98         {
99                 .hook           = ip6table_nat_local_fn,
100                 .owner          = THIS_MODULE,
101                 .pf             = NFPROTO_IPV6,
102                 .hooknum        = NF_INET_LOCAL_OUT,
103                 .priority       = NF_IP6_PRI_NAT_DST,
104         },
105         /* After packet filtering, change source */
106         {
107                 .hook           = ip6table_nat_fn,
108                 .owner          = THIS_MODULE,
109                 .pf             = NFPROTO_IPV6,
110                 .hooknum        = NF_INET_LOCAL_IN,
111                 .priority       = NF_IP6_PRI_NAT_SRC,
112         },
113 };
114
115 static int __net_init ip6table_nat_net_init(struct net *net)
116 {
117         struct ip6t_replace *repl;
118
119         repl = ip6t_alloc_initial_table(&nf_nat_ipv6_table);
120         if (repl == NULL)
121                 return -ENOMEM;
122         net->ipv6.ip6table_nat = ip6t_register_table(net, &nf_nat_ipv6_table, repl);
123         kfree(repl);
124         return PTR_ERR_OR_ZERO(net->ipv6.ip6table_nat);
125 }
126
127 static void __net_exit ip6table_nat_net_exit(struct net *net)
128 {
129         ip6t_unregister_table(net, net->ipv6.ip6table_nat);
130 }
131
132 static struct pernet_operations ip6table_nat_net_ops = {
133         .init   = ip6table_nat_net_init,
134         .exit   = ip6table_nat_net_exit,
135 };
136
137 static int __init ip6table_nat_init(void)
138 {
139         int err;
140
141         err = register_pernet_subsys(&ip6table_nat_net_ops);
142         if (err < 0)
143                 goto err1;
144
145         err = nf_register_hooks(nf_nat_ipv6_ops, ARRAY_SIZE(nf_nat_ipv6_ops));
146         if (err < 0)
147                 goto err2;
148         return 0;
149
150 err2:
151         unregister_pernet_subsys(&ip6table_nat_net_ops);
152 err1:
153         return err;
154 }
155
156 static void __exit ip6table_nat_exit(void)
157 {
158         nf_unregister_hooks(nf_nat_ipv6_ops, ARRAY_SIZE(nf_nat_ipv6_ops));
159         unregister_pernet_subsys(&ip6table_nat_net_ops);
160 }
161
162 module_init(ip6table_nat_init);
163 module_exit(ip6table_nat_exit);
164
165 MODULE_LICENSE("GPL");