blob: 138a24bc76ad9d215e1e9b836405774adaac02e7 [file] [log] [blame]
Patrick McHardyc7232c92012-08-26 19:14:06 +02001/* (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
Florian Westphalb9e69e12016-02-25 10:08:36 +010021static int __net_init iptable_nat_table_init(struct net *net);
22
Patrick McHardyc7232c92012-08-26 19:14:06 +020023static 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,
Florian Westphalb9e69e12016-02-25 10:08:36 +010031 .table_init = iptable_nat_table_init,
Patrick McHardyc7232c92012-08-26 19:14:06 +020032};
33
Eric W. Biederman06198b32015-09-18 14:33:06 -050034static unsigned int iptable_nat_do_chain(void *priv,
Pablo Neira Ayuso30766f42014-08-05 20:02:42 +020035 struct sk_buff *skb,
David S. Millerd7cf4082015-04-03 20:51:13 -040036 const struct nf_hook_state *state,
Pablo Neira Ayuso30766f42014-08-05 20:02:42 +020037 struct nf_conn *ct)
Patrick McHardyc7232c92012-08-26 19:14:06 +020038{
Eric W. Biederman6cb8ff3f12015-09-18 14:32:55 -050039 return ipt_do_table(skb, state, state->net->ipv4.nat_table);
Patrick McHardyc7232c92012-08-26 19:14:06 +020040}
41
Eric W. Biederman06198b32015-09-18 14:33:06 -050042static unsigned int iptable_nat_ipv4_fn(void *priv,
Pablo Neira Ayuso30766f42014-08-05 20:02:42 +020043 struct sk_buff *skb,
David S. Miller238e54c2015-04-03 20:32:56 -040044 const struct nf_hook_state *state)
Patrick McHardyc7232c92012-08-26 19:14:06 +020045{
Eric W. Biederman06198b32015-09-18 14:33:06 -050046 return nf_nat_ipv4_fn(priv, skb, state, iptable_nat_do_chain);
Patrick McHardyc7232c92012-08-26 19:14:06 +020047}
48
Eric W. Biederman06198b32015-09-18 14:33:06 -050049static unsigned int iptable_nat_ipv4_in(void *priv,
Pablo Neira Ayuso30766f42014-08-05 20:02:42 +020050 struct sk_buff *skb,
David S. Miller238e54c2015-04-03 20:32:56 -040051 const struct nf_hook_state *state)
Patrick McHardyc7232c92012-08-26 19:14:06 +020052{
Eric W. Biederman06198b32015-09-18 14:33:06 -050053 return nf_nat_ipv4_in(priv, skb, state, iptable_nat_do_chain);
Patrick McHardyc7232c92012-08-26 19:14:06 +020054}
55
Eric W. Biederman06198b32015-09-18 14:33:06 -050056static unsigned int iptable_nat_ipv4_out(void *priv,
Pablo Neira Ayuso30766f42014-08-05 20:02:42 +020057 struct sk_buff *skb,
David S. Miller238e54c2015-04-03 20:32:56 -040058 const struct nf_hook_state *state)
Patrick McHardyc7232c92012-08-26 19:14:06 +020059{
Eric W. Biederman06198b32015-09-18 14:33:06 -050060 return nf_nat_ipv4_out(priv, skb, state, iptable_nat_do_chain);
Patrick McHardyc7232c92012-08-26 19:14:06 +020061}
62
Eric W. Biederman06198b32015-09-18 14:33:06 -050063static unsigned int iptable_nat_ipv4_local_fn(void *priv,
Pablo Neira Ayuso30766f42014-08-05 20:02:42 +020064 struct sk_buff *skb,
David S. Miller238e54c2015-04-03 20:32:56 -040065 const struct nf_hook_state *state)
Patrick McHardyc7232c92012-08-26 19:14:06 +020066{
Eric W. Biederman06198b32015-09-18 14:33:06 -050067 return nf_nat_ipv4_local_fn(priv, skb, state, iptable_nat_do_chain);
Patrick McHardyc7232c92012-08-26 19:14:06 +020068}
69
70static struct nf_hook_ops nf_nat_ipv4_ops[] __read_mostly = {
71 /* Before packet filtering, change destination */
72 {
Pablo Neira Ayuso30766f42014-08-05 20:02:42 +020073 .hook = iptable_nat_ipv4_in,
Patrick McHardyc7232c92012-08-26 19:14:06 +020074 .pf = NFPROTO_IPV4,
75 .hooknum = NF_INET_PRE_ROUTING,
76 .priority = NF_IP_PRI_NAT_DST,
77 },
78 /* After packet filtering, change source */
79 {
Pablo Neira Ayuso30766f42014-08-05 20:02:42 +020080 .hook = iptable_nat_ipv4_out,
Patrick McHardyc7232c92012-08-26 19:14:06 +020081 .pf = NFPROTO_IPV4,
82 .hooknum = NF_INET_POST_ROUTING,
83 .priority = NF_IP_PRI_NAT_SRC,
84 },
85 /* Before packet filtering, change destination */
86 {
Pablo Neira Ayuso30766f42014-08-05 20:02:42 +020087 .hook = iptable_nat_ipv4_local_fn,
Patrick McHardyc7232c92012-08-26 19:14:06 +020088 .pf = NFPROTO_IPV4,
89 .hooknum = NF_INET_LOCAL_OUT,
90 .priority = NF_IP_PRI_NAT_DST,
91 },
92 /* After packet filtering, change source */
93 {
Pablo Neira Ayuso30766f42014-08-05 20:02:42 +020094 .hook = iptable_nat_ipv4_fn,
Patrick McHardyc7232c92012-08-26 19:14:06 +020095 .pf = NFPROTO_IPV4,
96 .hooknum = NF_INET_LOCAL_IN,
97 .priority = NF_IP_PRI_NAT_SRC,
98 },
99};
100
Florian Westphalb9e69e12016-02-25 10:08:36 +0100101static int __net_init iptable_nat_table_init(struct net *net)
Patrick McHardyc7232c92012-08-26 19:14:06 +0200102{
103 struct ipt_replace *repl;
Florian Westphala67dd262016-02-25 10:08:35 +0100104 int ret;
Patrick McHardyc7232c92012-08-26 19:14:06 +0200105
Florian Westphalb9e69e12016-02-25 10:08:36 +0100106 if (net->ipv4.nat_table)
107 return 0;
108
Patrick McHardyc7232c92012-08-26 19:14:06 +0200109 repl = ipt_alloc_initial_table(&nf_nat_ipv4_table);
110 if (repl == NULL)
111 return -ENOMEM;
Florian Westphala67dd262016-02-25 10:08:35 +0100112 ret = ipt_register_table(net, &nf_nat_ipv4_table, repl,
113 nf_nat_ipv4_ops, &net->ipv4.nat_table);
Patrick McHardyc7232c92012-08-26 19:14:06 +0200114 kfree(repl);
Florian Westphala67dd262016-02-25 10:08:35 +0100115 return ret;
Patrick McHardyc7232c92012-08-26 19:14:06 +0200116}
117
118static void __net_exit iptable_nat_net_exit(struct net *net)
119{
Florian Westphalb9e69e12016-02-25 10:08:36 +0100120 if (!net->ipv4.nat_table)
121 return;
Florian Westphala67dd262016-02-25 10:08:35 +0100122 ipt_unregister_table(net, net->ipv4.nat_table, nf_nat_ipv4_ops);
Florian Westphalb9e69e12016-02-25 10:08:36 +0100123 net->ipv4.nat_table = NULL;
Patrick McHardyc7232c92012-08-26 19:14:06 +0200124}
125
126static struct pernet_operations iptable_nat_net_ops = {
Patrick McHardyc7232c92012-08-26 19:14:06 +0200127 .exit = iptable_nat_net_exit,
128};
129
130static int __init iptable_nat_init(void)
131{
Florian Westphalb9e69e12016-02-25 10:08:36 +0100132 int ret = register_pernet_subsys(&iptable_nat_net_ops);
Patrick McHardyc7232c92012-08-26 19:14:06 +0200133
Florian Westphalb9e69e12016-02-25 10:08:36 +0100134 if (ret)
135 return ret;
Patrick McHardyc7232c92012-08-26 19:14:06 +0200136
Florian Westphalb9e69e12016-02-25 10:08:36 +0100137 ret = iptable_nat_table_init(&init_net);
138 if (ret)
139 unregister_pernet_subsys(&iptable_nat_net_ops);
140 return ret;
Patrick McHardyc7232c92012-08-26 19:14:06 +0200141}
142
143static void __exit iptable_nat_exit(void)
144{
Patrick McHardyc7232c92012-08-26 19:14:06 +0200145 unregister_pernet_subsys(&iptable_nat_net_ops);
146}
147
148module_init(iptable_nat_init);
149module_exit(iptable_nat_exit);
150
151MODULE_LICENSE("GPL");