projects/linux·blob master · refs

256 lines · 6.6 KiB

1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * (C) 1999-2001 Paul `Rusty' Russell
4 * (C) 2002-2006 Netfilter Core Team <[email protected]>
5 * (C) 2011 Patrick McHardy <[email protected]>
6 */
7
8#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
9
10#include <linux/module.h>
11#include <linux/skbuff.h>
12#include <linux/netfilter.h>
13#include <linux/netfilter/x_tables.h>
14#include <net/netfilter/nf_nat.h>
15
16static int xt_nat_checkentry_v0(const struct xt_tgchk_param *par)
17{
18 const struct nf_nat_ipv4_multi_range_compat *mr = par->targinfo;
19
20 if (mr->rangesize != 1) {
21 pr_info_ratelimited("multiple ranges no longer supported\n");
22 return -EINVAL;
23 }
24 return nf_ct_netns_get(par->net, par->family);
25}
26
27static int xt_nat_checkentry(const struct xt_tgchk_param *par)
28{
29 switch (par->family) {
30 case NFPROTO_IPV4:
31 case NFPROTO_IPV6:
32 case NFPROTO_INET:
33 break;
34 default:
35 return -EINVAL;
36 }
37
38 return nf_ct_netns_get(par->net, par->family);
39}
40
41static void xt_nat_destroy(const struct xt_tgdtor_param *par)
42{
43 nf_ct_netns_put(par->net, par->family);
44}
45
46static void xt_nat_convert_range(struct nf_nat_range2 *dst,
47 const struct nf_nat_ipv4_range *src)
48{
49 memset(&dst->min_addr, 0, sizeof(dst->min_addr));
50 memset(&dst->max_addr, 0, sizeof(dst->max_addr));
51 memset(&dst->base_proto, 0, sizeof(dst->base_proto));
52
53 dst->flags = src->flags;
54 dst->min_addr.ip = src->min_ip;
55 dst->max_addr.ip = src->max_ip;
56 dst->min_proto = src->min;
57 dst->max_proto = src->max;
58}
59
60static unsigned int
61xt_snat_target_v0(struct sk_buff *skb, const struct xt_action_param *par)
62{
63 const struct nf_nat_ipv4_multi_range_compat *mr = par->targinfo;
64 struct nf_nat_range2 range;
65 enum ip_conntrack_info ctinfo;
66 struct nf_conn *ct;
67
68 ct = nf_ct_get(skb, &ctinfo);
69 WARN_ON(!(ct != NULL &&
70 (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED ||
71 ctinfo == IP_CT_RELATED_REPLY)));
72
73 xt_nat_convert_range(&range, &mr->range[0]);
74 return nf_nat_setup_info(ct, &range, NF_NAT_MANIP_SRC);
75}
76
77static unsigned int
78xt_dnat_target_v0(struct sk_buff *skb, const struct xt_action_param *par)
79{
80 const struct nf_nat_ipv4_multi_range_compat *mr = par->targinfo;
81 struct nf_nat_range2 range;
82 enum ip_conntrack_info ctinfo;
83 struct nf_conn *ct;
84
85 ct = nf_ct_get(skb, &ctinfo);
86 WARN_ON(!(ct != NULL &&
87 (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED)));
88
89 xt_nat_convert_range(&range, &mr->range[0]);
90 return nf_nat_setup_info(ct, &range, NF_NAT_MANIP_DST);
91}
92
93static unsigned int
94xt_snat_target_v1(struct sk_buff *skb, const struct xt_action_param *par)
95{
96 const struct nf_nat_range *range_v1 = par->targinfo;
97 struct nf_nat_range2 range;
98 enum ip_conntrack_info ctinfo;
99 struct nf_conn *ct;
100
101 ct = nf_ct_get(skb, &ctinfo);
102 WARN_ON(!(ct != NULL &&
103 (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED ||
104 ctinfo == IP_CT_RELATED_REPLY)));
105
106 memcpy(&range, range_v1, sizeof(*range_v1));
107 memset(&range.base_proto, 0, sizeof(range.base_proto));
108
109 return nf_nat_setup_info(ct, &range, NF_NAT_MANIP_SRC);
110}
111
112static unsigned int
113xt_dnat_target_v1(struct sk_buff *skb, const struct xt_action_param *par)
114{
115 const struct nf_nat_range *range_v1 = par->targinfo;
116 struct nf_nat_range2 range;
117 enum ip_conntrack_info ctinfo;
118 struct nf_conn *ct;
119
120 ct = nf_ct_get(skb, &ctinfo);
121 WARN_ON(!(ct != NULL &&
122 (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED)));
123
124 memcpy(&range, range_v1, sizeof(*range_v1));
125 memset(&range.base_proto, 0, sizeof(range.base_proto));
126
127 return nf_nat_setup_info(ct, &range, NF_NAT_MANIP_DST);
128}
129
130static unsigned int
131xt_snat_target_v2(struct sk_buff *skb, const struct xt_action_param *par)
132{
133 const struct nf_nat_range2 *range = par->targinfo;
134 enum ip_conntrack_info ctinfo;
135 struct nf_conn *ct;
136
137 ct = nf_ct_get(skb, &ctinfo);
138 WARN_ON(!(ct != NULL &&
139 (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED ||
140 ctinfo == IP_CT_RELATED_REPLY)));
141
142 return nf_nat_setup_info(ct, range, NF_NAT_MANIP_SRC);
143}
144
145static unsigned int
146xt_dnat_target_v2(struct sk_buff *skb, const struct xt_action_param *par)
147{
148 const struct nf_nat_range2 *range = par->targinfo;
149 enum ip_conntrack_info ctinfo;
150 struct nf_conn *ct;
151
152 ct = nf_ct_get(skb, &ctinfo);
153 WARN_ON(!(ct != NULL &&
154 (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED)));
155
156 return nf_nat_setup_info(ct, range, NF_NAT_MANIP_DST);
157}
158
159static struct xt_target xt_nat_target_reg[] __read_mostly = {
160 {
161 .name = "SNAT",
162 .revision = 0,
163 .checkentry = xt_nat_checkentry_v0,
164 .destroy = xt_nat_destroy,
165 .target = xt_snat_target_v0,
166 .targetsize = sizeof(struct nf_nat_ipv4_multi_range_compat),
167 .family = NFPROTO_IPV4,
168 .table = "nat",
169 .hooks = (1 << NF_INET_POST_ROUTING) |
170 (1 << NF_INET_LOCAL_IN),
171 .me = THIS_MODULE,
172 },
173 {
174 .name = "DNAT",
175 .revision = 0,
176 .checkentry = xt_nat_checkentry_v0,
177 .destroy = xt_nat_destroy,
178 .target = xt_dnat_target_v0,
179 .targetsize = sizeof(struct nf_nat_ipv4_multi_range_compat),
180 .family = NFPROTO_IPV4,
181 .table = "nat",
182 .hooks = (1 << NF_INET_PRE_ROUTING) |
183 (1 << NF_INET_LOCAL_OUT),
184 .me = THIS_MODULE,
185 },
186 {
187 .name = "SNAT",
188 .revision = 1,
189 .checkentry = xt_nat_checkentry,
190 .destroy = xt_nat_destroy,
191 .target = xt_snat_target_v1,
192 .targetsize = sizeof(struct nf_nat_range),
193 .table = "nat",
194 .hooks = (1 << NF_INET_POST_ROUTING) |
195 (1 << NF_INET_LOCAL_IN),
196 .me = THIS_MODULE,
197 },
198 {
199 .name = "DNAT",
200 .revision = 1,
201 .checkentry = xt_nat_checkentry,
202 .destroy = xt_nat_destroy,
203 .target = xt_dnat_target_v1,
204 .targetsize = sizeof(struct nf_nat_range),
205 .table = "nat",
206 .hooks = (1 << NF_INET_PRE_ROUTING) |
207 (1 << NF_INET_LOCAL_OUT),
208 .me = THIS_MODULE,
209 },
210 {
211 .name = "SNAT",
212 .revision = 2,
213 .checkentry = xt_nat_checkentry,
214 .destroy = xt_nat_destroy,
215 .target = xt_snat_target_v2,
216 .targetsize = sizeof(struct nf_nat_range2),
217 .table = "nat",
218 .hooks = (1 << NF_INET_POST_ROUTING) |
219 (1 << NF_INET_LOCAL_IN),
220 .me = THIS_MODULE,
221 },
222 {
223 .name = "DNAT",
224 .revision = 2,
225 .checkentry = xt_nat_checkentry,
226 .destroy = xt_nat_destroy,
227 .target = xt_dnat_target_v2,
228 .targetsize = sizeof(struct nf_nat_range2),
229 .table = "nat",
230 .hooks = (1 << NF_INET_PRE_ROUTING) |
231 (1 << NF_INET_LOCAL_OUT),
232 .me = THIS_MODULE,
233 },
234};
235
236static int __init xt_nat_init(void)
237{
238 return xt_register_targets(xt_nat_target_reg,
239 ARRAY_SIZE(xt_nat_target_reg));
240}
241
242static void __exit xt_nat_exit(void)
243{
244 xt_unregister_targets(xt_nat_target_reg, ARRAY_SIZE(xt_nat_target_reg));
245}
246
247module_init(xt_nat_init);
248module_exit(xt_nat_exit);
249
250MODULE_LICENSE("GPL");
251MODULE_AUTHOR("Patrick McHardy <[email protected]>");
252MODULE_ALIAS("ipt_SNAT");
253MODULE_ALIAS("ipt_DNAT");
254MODULE_ALIAS("ip6t_SNAT");
255MODULE_ALIAS("ip6t_DNAT");
256MODULE_DESCRIPTION("SNAT and DNAT targets support");