GNU Linux-libre 4.19.211-gnu1
[releases.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 #include <net/netfilter/nf_nat_core.h>
19 #include <net/netfilter/nf_nat_l3proto.h>
20
21 static int __net_init iptable_nat_table_init(struct net *net);
22
23 static const struct xt_table nf_nat_ipv4_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_IPV4,
31         .table_init     = iptable_nat_table_init,
32 };
33
34 static unsigned int iptable_nat_do_chain(void *priv,
35                                          struct sk_buff *skb,
36                                          const struct nf_hook_state *state)
37 {
38         return ipt_do_table(skb, state, state->net->ipv4.nat_table);
39 }
40
41 static const struct nf_hook_ops nf_nat_ipv4_ops[] = {
42         {
43                 .hook           = iptable_nat_do_chain,
44                 .pf             = NFPROTO_IPV4,
45                 .hooknum        = NF_INET_PRE_ROUTING,
46                 .priority       = NF_IP_PRI_NAT_DST,
47         },
48         {
49                 .hook           = iptable_nat_do_chain,
50                 .pf             = NFPROTO_IPV4,
51                 .hooknum        = NF_INET_POST_ROUTING,
52                 .priority       = NF_IP_PRI_NAT_SRC,
53         },
54         {
55                 .hook           = iptable_nat_do_chain,
56                 .pf             = NFPROTO_IPV4,
57                 .hooknum        = NF_INET_LOCAL_OUT,
58                 .priority       = NF_IP_PRI_NAT_DST,
59         },
60         {
61                 .hook           = iptable_nat_do_chain,
62                 .pf             = NFPROTO_IPV4,
63                 .hooknum        = NF_INET_LOCAL_IN,
64                 .priority       = NF_IP_PRI_NAT_SRC,
65         },
66 };
67
68 static int ipt_nat_register_lookups(struct net *net)
69 {
70         int i, ret;
71
72         for (i = 0; i < ARRAY_SIZE(nf_nat_ipv4_ops); i++) {
73                 ret = nf_nat_l3proto_ipv4_register_fn(net, &nf_nat_ipv4_ops[i]);
74                 if (ret) {
75                         while (i)
76                                 nf_nat_l3proto_ipv4_unregister_fn(net, &nf_nat_ipv4_ops[--i]);
77
78                         return ret;
79                 }
80         }
81
82         return 0;
83 }
84
85 static void ipt_nat_unregister_lookups(struct net *net)
86 {
87         int i;
88
89         for (i = 0; i < ARRAY_SIZE(nf_nat_ipv4_ops); i++)
90                 nf_nat_l3proto_ipv4_unregister_fn(net, &nf_nat_ipv4_ops[i]);
91 }
92
93 static int __net_init iptable_nat_table_init(struct net *net)
94 {
95         struct ipt_replace *repl;
96         int ret;
97
98         if (net->ipv4.nat_table)
99                 return 0;
100
101         repl = ipt_alloc_initial_table(&nf_nat_ipv4_table);
102         if (repl == NULL)
103                 return -ENOMEM;
104         ret = ipt_register_table(net, &nf_nat_ipv4_table, repl,
105                                  NULL, &net->ipv4.nat_table);
106         if (ret < 0) {
107                 kfree(repl);
108                 return ret;
109         }
110
111         ret = ipt_nat_register_lookups(net);
112         if (ret < 0) {
113                 ipt_unregister_table(net, net->ipv4.nat_table, NULL);
114                 net->ipv4.nat_table = NULL;
115         }
116
117         kfree(repl);
118         return ret;
119 }
120
121 static void __net_exit iptable_nat_net_exit(struct net *net)
122 {
123         if (!net->ipv4.nat_table)
124                 return;
125         ipt_nat_unregister_lookups(net);
126         ipt_unregister_table(net, net->ipv4.nat_table, NULL);
127         net->ipv4.nat_table = NULL;
128 }
129
130 static struct pernet_operations iptable_nat_net_ops = {
131         .exit   = iptable_nat_net_exit,
132 };
133
134 static int __init iptable_nat_init(void)
135 {
136         int ret = register_pernet_subsys(&iptable_nat_net_ops);
137
138         if (ret)
139                 return ret;
140
141         ret = iptable_nat_table_init(&init_net);
142         if (ret)
143                 unregister_pernet_subsys(&iptable_nat_net_ops);
144         return ret;
145 }
146
147 static void __exit iptable_nat_exit(void)
148 {
149         unregister_pernet_subsys(&iptable_nat_net_ops);
150 }
151
152 module_init(iptable_nat_init);
153 module_exit(iptable_nat_exit);
154
155 MODULE_LICENSE("GPL");