1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2c7232c99SPatrick McHardy /*
3c7232c99SPatrick McHardy * (C) 1999-2001 Paul `Rusty' Russell
4c7232c99SPatrick McHardy * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org>
5c7232c99SPatrick McHardy * (C) 2011 Patrick McHardy <kaber@trash.net>
6c7232c99SPatrick McHardy */
7c7232c99SPatrick McHardy
8b2606644SFlorian Westphal #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
9b2606644SFlorian Westphal
10c7232c99SPatrick McHardy #include <linux/module.h>
11c7232c99SPatrick McHardy #include <linux/skbuff.h>
12c7232c99SPatrick McHardy #include <linux/netfilter.h>
13c7232c99SPatrick McHardy #include <linux/netfilter/x_tables.h>
14d2c5c103SFlorian Westphal #include <net/netfilter/nf_nat.h>
15c7232c99SPatrick McHardy
xt_nat_checkentry_v0(const struct xt_tgchk_param * par)16c7232c99SPatrick McHardy static int xt_nat_checkentry_v0(const struct xt_tgchk_param *par)
17c7232c99SPatrick McHardy {
18c7232c99SPatrick McHardy const struct nf_nat_ipv4_multi_range_compat *mr = par->targinfo;
19c7232c99SPatrick McHardy
20c7232c99SPatrick McHardy if (mr->rangesize != 1) {
21b2606644SFlorian Westphal pr_info_ratelimited("multiple ranges no longer supported\n");
22c7232c99SPatrick McHardy return -EINVAL;
23c7232c99SPatrick McHardy }
24a357b3f8SFlorian Westphal return nf_ct_netns_get(par->net, par->family);
25a357b3f8SFlorian Westphal }
26a357b3f8SFlorian Westphal
xt_nat_checkentry(const struct xt_tgchk_param * par)27a357b3f8SFlorian Westphal static int xt_nat_checkentry(const struct xt_tgchk_param *par)
28a357b3f8SFlorian Westphal {
29a357b3f8SFlorian Westphal return nf_ct_netns_get(par->net, par->family);
30a357b3f8SFlorian Westphal }
31a357b3f8SFlorian Westphal
xt_nat_destroy(const struct xt_tgdtor_param * par)32a357b3f8SFlorian Westphal static void xt_nat_destroy(const struct xt_tgdtor_param *par)
33a357b3f8SFlorian Westphal {
34a357b3f8SFlorian Westphal nf_ct_netns_put(par->net, par->family);
35c7232c99SPatrick McHardy }
36c7232c99SPatrick McHardy
xt_nat_convert_range(struct nf_nat_range2 * dst,const struct nf_nat_ipv4_range * src)372eb0f624SThierry Du Tre static void xt_nat_convert_range(struct nf_nat_range2 *dst,
38c7232c99SPatrick McHardy const struct nf_nat_ipv4_range *src)
39c7232c99SPatrick McHardy {
40c7232c99SPatrick McHardy memset(&dst->min_addr, 0, sizeof(dst->min_addr));
41c7232c99SPatrick McHardy memset(&dst->max_addr, 0, sizeof(dst->max_addr));
422eb0f624SThierry Du Tre memset(&dst->base_proto, 0, sizeof(dst->base_proto));
43c7232c99SPatrick McHardy
44c7232c99SPatrick McHardy dst->flags = src->flags;
45c7232c99SPatrick McHardy dst->min_addr.ip = src->min_ip;
46c7232c99SPatrick McHardy dst->max_addr.ip = src->max_ip;
47c7232c99SPatrick McHardy dst->min_proto = src->min;
48c7232c99SPatrick McHardy dst->max_proto = src->max;
49c7232c99SPatrick McHardy }
50c7232c99SPatrick McHardy
51c7232c99SPatrick McHardy static unsigned int
xt_snat_target_v0(struct sk_buff * skb,const struct xt_action_param * par)52c7232c99SPatrick McHardy xt_snat_target_v0(struct sk_buff *skb, const struct xt_action_param *par)
53c7232c99SPatrick McHardy {
54c7232c99SPatrick McHardy const struct nf_nat_ipv4_multi_range_compat *mr = par->targinfo;
552eb0f624SThierry Du Tre struct nf_nat_range2 range;
56c7232c99SPatrick McHardy enum ip_conntrack_info ctinfo;
57c7232c99SPatrick McHardy struct nf_conn *ct;
58c7232c99SPatrick McHardy
59c7232c99SPatrick McHardy ct = nf_ct_get(skb, &ctinfo);
6044d6e2f2SVarsha Rao WARN_ON(!(ct != NULL &&
61c7232c99SPatrick McHardy (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED ||
6244d6e2f2SVarsha Rao ctinfo == IP_CT_RELATED_REPLY)));
63c7232c99SPatrick McHardy
64c7232c99SPatrick McHardy xt_nat_convert_range(&range, &mr->range[0]);
65c7232c99SPatrick McHardy return nf_nat_setup_info(ct, &range, NF_NAT_MANIP_SRC);
66c7232c99SPatrick McHardy }
67c7232c99SPatrick McHardy
68c7232c99SPatrick McHardy static unsigned int
xt_dnat_target_v0(struct sk_buff * skb,const struct xt_action_param * par)69c7232c99SPatrick McHardy xt_dnat_target_v0(struct sk_buff *skb, const struct xt_action_param *par)
70c7232c99SPatrick McHardy {
71c7232c99SPatrick McHardy const struct nf_nat_ipv4_multi_range_compat *mr = par->targinfo;
722eb0f624SThierry Du Tre struct nf_nat_range2 range;
73c7232c99SPatrick McHardy enum ip_conntrack_info ctinfo;
74c7232c99SPatrick McHardy struct nf_conn *ct;
75c7232c99SPatrick McHardy
76c7232c99SPatrick McHardy ct = nf_ct_get(skb, &ctinfo);
7744d6e2f2SVarsha Rao WARN_ON(!(ct != NULL &&
7844d6e2f2SVarsha Rao (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED)));
79c7232c99SPatrick McHardy
80c7232c99SPatrick McHardy xt_nat_convert_range(&range, &mr->range[0]);
81c7232c99SPatrick McHardy return nf_nat_setup_info(ct, &range, NF_NAT_MANIP_DST);
82c7232c99SPatrick McHardy }
83c7232c99SPatrick McHardy
84c7232c99SPatrick McHardy static unsigned int
xt_snat_target_v1(struct sk_buff * skb,const struct xt_action_param * par)85c7232c99SPatrick McHardy xt_snat_target_v1(struct sk_buff *skb, const struct xt_action_param *par)
86c7232c99SPatrick McHardy {
872eb0f624SThierry Du Tre const struct nf_nat_range *range_v1 = par->targinfo;
882eb0f624SThierry Du Tre struct nf_nat_range2 range;
892eb0f624SThierry Du Tre enum ip_conntrack_info ctinfo;
902eb0f624SThierry Du Tre struct nf_conn *ct;
912eb0f624SThierry Du Tre
922eb0f624SThierry Du Tre ct = nf_ct_get(skb, &ctinfo);
932eb0f624SThierry Du Tre WARN_ON(!(ct != NULL &&
942eb0f624SThierry Du Tre (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED ||
952eb0f624SThierry Du Tre ctinfo == IP_CT_RELATED_REPLY)));
962eb0f624SThierry Du Tre
972eb0f624SThierry Du Tre memcpy(&range, range_v1, sizeof(*range_v1));
982eb0f624SThierry Du Tre memset(&range.base_proto, 0, sizeof(range.base_proto));
992eb0f624SThierry Du Tre
1002eb0f624SThierry Du Tre return nf_nat_setup_info(ct, &range, NF_NAT_MANIP_SRC);
1012eb0f624SThierry Du Tre }
1022eb0f624SThierry Du Tre
1032eb0f624SThierry Du Tre static unsigned int
xt_dnat_target_v1(struct sk_buff * skb,const struct xt_action_param * par)1042eb0f624SThierry Du Tre xt_dnat_target_v1(struct sk_buff *skb, const struct xt_action_param *par)
1052eb0f624SThierry Du Tre {
1062eb0f624SThierry Du Tre const struct nf_nat_range *range_v1 = par->targinfo;
1072eb0f624SThierry Du Tre struct nf_nat_range2 range;
1082eb0f624SThierry Du Tre enum ip_conntrack_info ctinfo;
1092eb0f624SThierry Du Tre struct nf_conn *ct;
1102eb0f624SThierry Du Tre
1112eb0f624SThierry Du Tre ct = nf_ct_get(skb, &ctinfo);
1122eb0f624SThierry Du Tre WARN_ON(!(ct != NULL &&
1132eb0f624SThierry Du Tre (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED)));
1142eb0f624SThierry Du Tre
1152eb0f624SThierry Du Tre memcpy(&range, range_v1, sizeof(*range_v1));
1162eb0f624SThierry Du Tre memset(&range.base_proto, 0, sizeof(range.base_proto));
1172eb0f624SThierry Du Tre
1182eb0f624SThierry Du Tre return nf_nat_setup_info(ct, &range, NF_NAT_MANIP_DST);
1192eb0f624SThierry Du Tre }
1202eb0f624SThierry Du Tre
1212eb0f624SThierry Du Tre static unsigned int
xt_snat_target_v2(struct sk_buff * skb,const struct xt_action_param * par)1222eb0f624SThierry Du Tre xt_snat_target_v2(struct sk_buff *skb, const struct xt_action_param *par)
1232eb0f624SThierry Du Tre {
1242eb0f624SThierry Du Tre const struct nf_nat_range2 *range = par->targinfo;
125c7232c99SPatrick McHardy enum ip_conntrack_info ctinfo;
126c7232c99SPatrick McHardy struct nf_conn *ct;
127c7232c99SPatrick McHardy
128c7232c99SPatrick McHardy ct = nf_ct_get(skb, &ctinfo);
12944d6e2f2SVarsha Rao WARN_ON(!(ct != NULL &&
130c7232c99SPatrick McHardy (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED ||
13144d6e2f2SVarsha Rao ctinfo == IP_CT_RELATED_REPLY)));
132c7232c99SPatrick McHardy
133c7232c99SPatrick McHardy return nf_nat_setup_info(ct, range, NF_NAT_MANIP_SRC);
134c7232c99SPatrick McHardy }
135c7232c99SPatrick McHardy
136c7232c99SPatrick McHardy static unsigned int
xt_dnat_target_v2(struct sk_buff * skb,const struct xt_action_param * par)1372eb0f624SThierry Du Tre xt_dnat_target_v2(struct sk_buff *skb, const struct xt_action_param *par)
138c7232c99SPatrick McHardy {
1392eb0f624SThierry Du Tre const struct nf_nat_range2 *range = par->targinfo;
140c7232c99SPatrick McHardy enum ip_conntrack_info ctinfo;
141c7232c99SPatrick McHardy struct nf_conn *ct;
142c7232c99SPatrick McHardy
143c7232c99SPatrick McHardy ct = nf_ct_get(skb, &ctinfo);
14444d6e2f2SVarsha Rao WARN_ON(!(ct != NULL &&
14544d6e2f2SVarsha Rao (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED)));
146c7232c99SPatrick McHardy
147c7232c99SPatrick McHardy return nf_nat_setup_info(ct, range, NF_NAT_MANIP_DST);
148c7232c99SPatrick McHardy }
149c7232c99SPatrick McHardy
150c7232c99SPatrick McHardy static struct xt_target xt_nat_target_reg[] __read_mostly = {
151c7232c99SPatrick McHardy {
152c7232c99SPatrick McHardy .name = "SNAT",
153c7232c99SPatrick McHardy .revision = 0,
154c7232c99SPatrick McHardy .checkentry = xt_nat_checkentry_v0,
155a357b3f8SFlorian Westphal .destroy = xt_nat_destroy,
156c7232c99SPatrick McHardy .target = xt_snat_target_v0,
157c7232c99SPatrick McHardy .targetsize = sizeof(struct nf_nat_ipv4_multi_range_compat),
158c7232c99SPatrick McHardy .family = NFPROTO_IPV4,
159c7232c99SPatrick McHardy .table = "nat",
160c7232c99SPatrick McHardy .hooks = (1 << NF_INET_POST_ROUTING) |
161939ccba4SElison Niven (1 << NF_INET_LOCAL_IN),
162c7232c99SPatrick McHardy .me = THIS_MODULE,
163c7232c99SPatrick McHardy },
164c7232c99SPatrick McHardy {
165c7232c99SPatrick McHardy .name = "DNAT",
166c7232c99SPatrick McHardy .revision = 0,
167c7232c99SPatrick McHardy .checkentry = xt_nat_checkentry_v0,
168a357b3f8SFlorian Westphal .destroy = xt_nat_destroy,
169c7232c99SPatrick McHardy .target = xt_dnat_target_v0,
170c7232c99SPatrick McHardy .targetsize = sizeof(struct nf_nat_ipv4_multi_range_compat),
171c7232c99SPatrick McHardy .family = NFPROTO_IPV4,
172c7232c99SPatrick McHardy .table = "nat",
173c7232c99SPatrick McHardy .hooks = (1 << NF_INET_PRE_ROUTING) |
174939ccba4SElison Niven (1 << NF_INET_LOCAL_OUT),
175c7232c99SPatrick McHardy .me = THIS_MODULE,
176c7232c99SPatrick McHardy },
177c7232c99SPatrick McHardy {
178c7232c99SPatrick McHardy .name = "SNAT",
179c7232c99SPatrick McHardy .revision = 1,
180a357b3f8SFlorian Westphal .checkentry = xt_nat_checkentry,
181a357b3f8SFlorian Westphal .destroy = xt_nat_destroy,
182c7232c99SPatrick McHardy .target = xt_snat_target_v1,
183c7232c99SPatrick McHardy .targetsize = sizeof(struct nf_nat_range),
184c7232c99SPatrick McHardy .table = "nat",
185c7232c99SPatrick McHardy .hooks = (1 << NF_INET_POST_ROUTING) |
186939ccba4SElison Niven (1 << NF_INET_LOCAL_IN),
187c7232c99SPatrick McHardy .me = THIS_MODULE,
188c7232c99SPatrick McHardy },
189c7232c99SPatrick McHardy {
190c7232c99SPatrick McHardy .name = "DNAT",
191c7232c99SPatrick McHardy .revision = 1,
192a357b3f8SFlorian Westphal .checkentry = xt_nat_checkentry,
193a357b3f8SFlorian Westphal .destroy = xt_nat_destroy,
194c7232c99SPatrick McHardy .target = xt_dnat_target_v1,
195c7232c99SPatrick McHardy .targetsize = sizeof(struct nf_nat_range),
196c7232c99SPatrick McHardy .table = "nat",
197c7232c99SPatrick McHardy .hooks = (1 << NF_INET_PRE_ROUTING) |
198939ccba4SElison Niven (1 << NF_INET_LOCAL_OUT),
199c7232c99SPatrick McHardy .me = THIS_MODULE,
200c7232c99SPatrick McHardy },
2012eb0f624SThierry Du Tre {
2022eb0f624SThierry Du Tre .name = "SNAT",
2032eb0f624SThierry Du Tre .revision = 2,
2042eb0f624SThierry Du Tre .checkentry = xt_nat_checkentry,
2052eb0f624SThierry Du Tre .destroy = xt_nat_destroy,
2062eb0f624SThierry Du Tre .target = xt_snat_target_v2,
2072eb0f624SThierry Du Tre .targetsize = sizeof(struct nf_nat_range2),
2082eb0f624SThierry Du Tre .table = "nat",
2092eb0f624SThierry Du Tre .hooks = (1 << NF_INET_POST_ROUTING) |
2102eb0f624SThierry Du Tre (1 << NF_INET_LOCAL_IN),
2112eb0f624SThierry Du Tre .me = THIS_MODULE,
2122eb0f624SThierry Du Tre },
2132eb0f624SThierry Du Tre {
2142eb0f624SThierry Du Tre .name = "DNAT",
2152eb0f624SThierry Du Tre .revision = 2,
216cb20f2d2SPaolo Abeni .checkentry = xt_nat_checkentry,
217cb20f2d2SPaolo Abeni .destroy = xt_nat_destroy,
2182eb0f624SThierry Du Tre .target = xt_dnat_target_v2,
2192eb0f624SThierry Du Tre .targetsize = sizeof(struct nf_nat_range2),
2202eb0f624SThierry Du Tre .table = "nat",
2212eb0f624SThierry Du Tre .hooks = (1 << NF_INET_PRE_ROUTING) |
2222eb0f624SThierry Du Tre (1 << NF_INET_LOCAL_OUT),
2232eb0f624SThierry Du Tre .me = THIS_MODULE,
2242eb0f624SThierry Du Tre },
225c7232c99SPatrick McHardy };
226c7232c99SPatrick McHardy
xt_nat_init(void)227c7232c99SPatrick McHardy static int __init xt_nat_init(void)
228c7232c99SPatrick McHardy {
229c7232c99SPatrick McHardy return xt_register_targets(xt_nat_target_reg,
230c7232c99SPatrick McHardy ARRAY_SIZE(xt_nat_target_reg));
231c7232c99SPatrick McHardy }
232c7232c99SPatrick McHardy
xt_nat_exit(void)233c7232c99SPatrick McHardy static void __exit xt_nat_exit(void)
234c7232c99SPatrick McHardy {
235c7232c99SPatrick McHardy xt_unregister_targets(xt_nat_target_reg, ARRAY_SIZE(xt_nat_target_reg));
236c7232c99SPatrick McHardy }
237c7232c99SPatrick McHardy
238c7232c99SPatrick McHardy module_init(xt_nat_init);
239c7232c99SPatrick McHardy module_exit(xt_nat_exit);
240c7232c99SPatrick McHardy
241c7232c99SPatrick McHardy MODULE_LICENSE("GPL");
24258a317f1SPatrick McHardy MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
243c7232c99SPatrick McHardy MODULE_ALIAS("ipt_SNAT");
244c7232c99SPatrick McHardy MODULE_ALIAS("ipt_DNAT");
24558a317f1SPatrick McHardy MODULE_ALIAS("ip6t_SNAT");
24658a317f1SPatrick McHardy MODULE_ALIAS("ip6t_DNAT");
2474cacc395SRob Gill MODULE_DESCRIPTION("SNAT and DNAT targets support");
248