xref: /openbmc/linux/net/netfilter/xt_nat.c (revision 4cacc395)
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