Merge tag 'ntb-5.1' of git://github.com/jonmason/ntb
[linux-2.6-microblaze.git] / net / ipv4 / netfilter / iptable_nat.c
1 /* (C) 1999-2001 Paul `Rusty' Russell
2  * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org>
3  * (C) 2011 Patrick McHardy <kaber@trash.net>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation.
8  */
9
10 #include <linux/module.h>
11 #include <linux/netfilter.h>
12 #include <linux/netfilter_ipv4.h>
13 #include <linux/netfilter_ipv4/ip_tables.h>
14 #include <linux/ip.h>
15 #include <net/ip.h>
16
17 #include <net/netfilter/nf_nat.h>
18
19 static int __net_init iptable_nat_table_init(struct net *net);
20
21 static const struct xt_table nf_nat_ipv4_table = {
22         .name           = "nat",
23         .valid_hooks    = (1 << NF_INET_PRE_ROUTING) |
24                           (1 << NF_INET_POST_ROUTING) |
25                           (1 << NF_INET_LOCAL_OUT) |
26                           (1 << NF_INET_LOCAL_IN),
27         .me             = THIS_MODULE,
28         .af             = NFPROTO_IPV4,
29         .table_init     = iptable_nat_table_init,
30 };
31
32 static unsigned int iptable_nat_do_chain(void *priv,
33                                          struct sk_buff *skb,
34                                          const struct nf_hook_state *state)
35 {
36         return ipt_do_table(skb, state, state->net->ipv4.nat_table);
37 }
38
39 static const struct nf_hook_ops nf_nat_ipv4_ops[] = {
40         {
41                 .hook           = iptable_nat_do_chain,
42                 .pf             = NFPROTO_IPV4,
43                 .hooknum        = NF_INET_PRE_ROUTING,
44                 .priority       = NF_IP_PRI_NAT_DST,
45         },
46         {
47                 .hook           = iptable_nat_do_chain,
48                 .pf             = NFPROTO_IPV4,
49                 .hooknum        = NF_INET_POST_ROUTING,
50                 .priority       = NF_IP_PRI_NAT_SRC,
51         },
52         {
53                 .hook           = iptable_nat_do_chain,
54                 .pf             = NFPROTO_IPV4,
55                 .hooknum        = NF_INET_LOCAL_OUT,
56                 .priority       = NF_IP_PRI_NAT_DST,
57         },
58         {
59                 .hook           = iptable_nat_do_chain,
60                 .pf             = NFPROTO_IPV4,
61                 .hooknum        = NF_INET_LOCAL_IN,
62                 .priority       = NF_IP_PRI_NAT_SRC,
63         },
64 };
65
66 static int ipt_nat_register_lookups(struct net *net)
67 {
68         int i, ret;
69
70         for (i = 0; i < ARRAY_SIZE(nf_nat_ipv4_ops); i++) {
71                 ret = nf_nat_ipv4_register_fn(net, &nf_nat_ipv4_ops[i]);
72                 if (ret) {
73                         while (i)
74                                 nf_nat_ipv4_unregister_fn(net, &nf_nat_ipv4_ops[--i]);
75
76                         return ret;
77                 }
78         }
79
80         return 0;
81 }
82
83 static void ipt_nat_unregister_lookups(struct net *net)
84 {
85         int i;
86
87         for (i = 0; i < ARRAY_SIZE(nf_nat_ipv4_ops); i++)
88                 nf_nat_ipv4_unregister_fn(net, &nf_nat_ipv4_ops[i]);
89 }
90
91 static int __net_init iptable_nat_table_init(struct net *net)
92 {
93         struct ipt_replace *repl;
94         int ret;
95
96         if (net->ipv4.nat_table)
97                 return 0;
98
99         repl = ipt_alloc_initial_table(&nf_nat_ipv4_table);
100         if (repl == NULL)
101                 return -ENOMEM;
102         ret = ipt_register_table(net, &nf_nat_ipv4_table, repl,
103                                  NULL, &net->ipv4.nat_table);
104         if (ret < 0) {
105                 kfree(repl);
106                 return ret;
107         }
108
109         ret = ipt_nat_register_lookups(net);
110         if (ret < 0) {
111                 ipt_unregister_table(net, net->ipv4.nat_table, NULL);
112                 net->ipv4.nat_table = NULL;
113         }
114
115         kfree(repl);
116         return ret;
117 }
118
119 static void __net_exit iptable_nat_net_exit(struct net *net)
120 {
121         if (!net->ipv4.nat_table)
122                 return;
123         ipt_nat_unregister_lookups(net);
124         ipt_unregister_table(net, net->ipv4.nat_table, NULL);
125         net->ipv4.nat_table = NULL;
126 }
127
128 static struct pernet_operations iptable_nat_net_ops = {
129         .exit   = iptable_nat_net_exit,
130 };
131
132 static int __init iptable_nat_init(void)
133 {
134         int ret = register_pernet_subsys(&iptable_nat_net_ops);
135
136         if (ret)
137                 return ret;
138
139         ret = iptable_nat_table_init(&init_net);
140         if (ret)
141                 unregister_pernet_subsys(&iptable_nat_net_ops);
142         return ret;
143 }
144
145 static void __exit iptable_nat_exit(void)
146 {
147         unregister_pernet_subsys(&iptable_nat_net_ops);
148 }
149
150 module_init(iptable_nat_init);
151 module_exit(iptable_nat_exit);
152
153 MODULE_LICENSE("GPL");