diff options
author | Pablo Neira Ayuso <pablo@netfilter.org> | 2014-08-25 06:05:27 -0400 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2014-09-09 10:30:00 -0400 |
commit | 2a5538e9aa4929329813bee69922c9ae4990fcad (patch) | |
tree | 66f4331151c6695ca4d0e174d0c233847de22862 /net | |
parent | 65cd90ac765fb6960f1e3815cc31972fc4599c37 (diff) |
netfilter: nat: move specific NAT IPv6 to core
Move the specific NAT IPv6 core functions that are called from the
hooks from ip6table_nat.c to nf_nat_l3proto_ipv6.c. This prepares the
ground to allow iptables and nft to use the same NAT engine code that
comes in a follow up patch.
This also renames nf_nat_ipv6_fn to nft_nat_ipv6_fn in
net/ipv6/netfilter/nft_chain_nat_ipv6.c to avoid a compilation breakage.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'net')
-rw-r--r-- | net/ipv6/netfilter/ip6table_nat.c | 233 | ||||
-rw-r--r-- | net/ipv6/netfilter/nf_nat_l3proto_ipv6.c | 199 | ||||
-rw-r--r-- | net/ipv6/netfilter/nft_chain_nat_ipv6.c | 10 |
3 files changed, 238 insertions, 204 deletions
diff --git a/net/ipv6/netfilter/ip6table_nat.c b/net/ipv6/netfilter/ip6table_nat.c index 387d8b8fc18d..b0634ac996b7 100644 --- a/net/ipv6/netfilter/ip6table_nat.c +++ b/net/ipv6/netfilter/ip6table_nat.c | |||
@@ -30,222 +30,57 @@ static const struct xt_table nf_nat_ipv6_table = { | |||
30 | .af = NFPROTO_IPV6, | 30 | .af = NFPROTO_IPV6, |
31 | }; | 31 | }; |
32 | 32 | ||
33 | static unsigned int alloc_null_binding(struct nf_conn *ct, unsigned int hooknum) | 33 | static unsigned int ip6table_nat_do_chain(const struct nf_hook_ops *ops, |
34 | { | 34 | struct sk_buff *skb, |
35 | /* Force range to this IP; let proto decide mapping for | 35 | const struct net_device *in, |
36 | * per-proto parts (hence not IP_NAT_RANGE_PROTO_SPECIFIED). | 36 | const struct net_device *out, |
37 | */ | 37 | struct nf_conn *ct) |
38 | struct nf_nat_range range; | ||
39 | |||
40 | range.flags = 0; | ||
41 | pr_debug("Allocating NULL binding for %p (%pI6)\n", ct, | ||
42 | HOOK2MANIP(hooknum) == NF_NAT_MANIP_SRC ? | ||
43 | &ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip6 : | ||
44 | &ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip6); | ||
45 | |||
46 | return nf_nat_setup_info(ct, &range, HOOK2MANIP(hooknum)); | ||
47 | } | ||
48 | |||
49 | static unsigned int nf_nat_rule_find(struct sk_buff *skb, unsigned int hooknum, | ||
50 | const struct net_device *in, | ||
51 | const struct net_device *out, | ||
52 | struct nf_conn *ct) | ||
53 | { | 38 | { |
54 | struct net *net = nf_ct_net(ct); | 39 | struct net *net = nf_ct_net(ct); |
55 | unsigned int ret; | ||
56 | 40 | ||
57 | ret = ip6t_do_table(skb, hooknum, in, out, net->ipv6.ip6table_nat); | 41 | return ip6t_do_table(skb, ops->hooknum, in, out, net->ipv6.ip6table_nat); |
58 | if (ret == NF_ACCEPT) { | ||
59 | if (!nf_nat_initialized(ct, HOOK2MANIP(hooknum))) | ||
60 | ret = alloc_null_binding(ct, hooknum); | ||
61 | } | ||
62 | return ret; | ||
63 | } | 42 | } |
64 | 43 | ||
65 | static unsigned int | 44 | static unsigned int ip6table_nat_fn(const struct nf_hook_ops *ops, |
66 | nf_nat_ipv6_fn(const struct nf_hook_ops *ops, | 45 | struct sk_buff *skb, |
67 | struct sk_buff *skb, | 46 | const struct net_device *in, |
68 | const struct net_device *in, | 47 | const struct net_device *out, |
69 | const struct net_device *out, | 48 | int (*okfn)(struct sk_buff *)) |
70 | int (*okfn)(struct sk_buff *)) | ||
71 | { | 49 | { |
72 | struct nf_conn *ct; | 50 | return nf_nat_ipv6_fn(ops, skb, in, out, ip6table_nat_do_chain); |
73 | enum ip_conntrack_info ctinfo; | ||
74 | struct nf_conn_nat *nat; | ||
75 | enum nf_nat_manip_type maniptype = HOOK2MANIP(ops->hooknum); | ||
76 | __be16 frag_off; | ||
77 | int hdrlen; | ||
78 | u8 nexthdr; | ||
79 | |||
80 | ct = nf_ct_get(skb, &ctinfo); | ||
81 | /* Can't track? It's not due to stress, or conntrack would | ||
82 | * have dropped it. Hence it's the user's responsibilty to | ||
83 | * packet filter it out, or implement conntrack/NAT for that | ||
84 | * protocol. 8) --RR | ||
85 | */ | ||
86 | if (!ct) | ||
87 | return NF_ACCEPT; | ||
88 | |||
89 | /* Don't try to NAT if this packet is not conntracked */ | ||
90 | if (nf_ct_is_untracked(ct)) | ||
91 | return NF_ACCEPT; | ||
92 | |||
93 | nat = nf_ct_nat_ext_add(ct); | ||
94 | if (nat == NULL) | ||
95 | return NF_ACCEPT; | ||
96 | |||
97 | switch (ctinfo) { | ||
98 | case IP_CT_RELATED: | ||
99 | case IP_CT_RELATED_REPLY: | ||
100 | nexthdr = ipv6_hdr(skb)->nexthdr; | ||
101 | hdrlen = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), | ||
102 | &nexthdr, &frag_off); | ||
103 | |||
104 | if (hdrlen >= 0 && nexthdr == IPPROTO_ICMPV6) { | ||
105 | if (!nf_nat_icmpv6_reply_translation(skb, ct, ctinfo, | ||
106 | ops->hooknum, | ||
107 | hdrlen)) | ||
108 | return NF_DROP; | ||
109 | else | ||
110 | return NF_ACCEPT; | ||
111 | } | ||
112 | /* Fall thru... (Only ICMPs can be IP_CT_IS_REPLY) */ | ||
113 | case IP_CT_NEW: | ||
114 | /* Seen it before? This can happen for loopback, retrans, | ||
115 | * or local packets. | ||
116 | */ | ||
117 | if (!nf_nat_initialized(ct, maniptype)) { | ||
118 | unsigned int ret; | ||
119 | |||
120 | ret = nf_nat_rule_find(skb, ops->hooknum, in, out, ct); | ||
121 | if (ret != NF_ACCEPT) | ||
122 | return ret; | ||
123 | } else { | ||
124 | pr_debug("Already setup manip %s for ct %p\n", | ||
125 | maniptype == NF_NAT_MANIP_SRC ? "SRC" : "DST", | ||
126 | ct); | ||
127 | if (nf_nat_oif_changed(ops->hooknum, ctinfo, nat, out)) | ||
128 | goto oif_changed; | ||
129 | } | ||
130 | break; | ||
131 | |||
132 | default: | ||
133 | /* ESTABLISHED */ | ||
134 | NF_CT_ASSERT(ctinfo == IP_CT_ESTABLISHED || | ||
135 | ctinfo == IP_CT_ESTABLISHED_REPLY); | ||
136 | if (nf_nat_oif_changed(ops->hooknum, ctinfo, nat, out)) | ||
137 | goto oif_changed; | ||
138 | } | ||
139 | |||
140 | return nf_nat_packet(ct, ctinfo, ops->hooknum, skb); | ||
141 | |||
142 | oif_changed: | ||
143 | nf_ct_kill_acct(ct, ctinfo, skb); | ||
144 | return NF_DROP; | ||
145 | } | 51 | } |
146 | 52 | ||
147 | static unsigned int | 53 | static unsigned int ip6table_nat_in(const struct nf_hook_ops *ops, |
148 | nf_nat_ipv6_in(const struct nf_hook_ops *ops, | 54 | struct sk_buff *skb, |
149 | struct sk_buff *skb, | 55 | const struct net_device *in, |
150 | const struct net_device *in, | 56 | const struct net_device *out, |
151 | const struct net_device *out, | 57 | int (*okfn)(struct sk_buff *)) |
152 | int (*okfn)(struct sk_buff *)) | ||
153 | { | 58 | { |
154 | unsigned int ret; | 59 | return nf_nat_ipv6_in(ops, skb, in, out, ip6table_nat_do_chain); |
155 | struct in6_addr daddr = ipv6_hdr(skb)->daddr; | ||
156 | |||
157 | ret = nf_nat_ipv6_fn(ops, skb, in, out, okfn); | ||
158 | if (ret != NF_DROP && ret != NF_STOLEN && | ||
159 | ipv6_addr_cmp(&daddr, &ipv6_hdr(skb)->daddr)) | ||
160 | skb_dst_drop(skb); | ||
161 | |||
162 | return ret; | ||
163 | } | 60 | } |
164 | 61 | ||
165 | static unsigned int | 62 | static unsigned int ip6table_nat_out(const struct nf_hook_ops *ops, |
166 | nf_nat_ipv6_out(const struct nf_hook_ops *ops, | 63 | struct sk_buff *skb, |
167 | struct sk_buff *skb, | 64 | const struct net_device *in, |
168 | const struct net_device *in, | 65 | const struct net_device *out, |
169 | const struct net_device *out, | 66 | int (*okfn)(struct sk_buff *)) |
170 | int (*okfn)(struct sk_buff *)) | ||
171 | { | 67 | { |
172 | #ifdef CONFIG_XFRM | 68 | return nf_nat_ipv6_out(ops, skb, in, out, ip6table_nat_do_chain); |
173 | const struct nf_conn *ct; | ||
174 | enum ip_conntrack_info ctinfo; | ||
175 | int err; | ||
176 | #endif | ||
177 | unsigned int ret; | ||
178 | |||
179 | /* root is playing with raw sockets. */ | ||
180 | if (skb->len < sizeof(struct ipv6hdr)) | ||
181 | return NF_ACCEPT; | ||
182 | |||
183 | ret = nf_nat_ipv6_fn(ops, skb, in, out, okfn); | ||
184 | #ifdef CONFIG_XFRM | ||
185 | if (ret != NF_DROP && ret != NF_STOLEN && | ||
186 | !(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) && | ||
187 | (ct = nf_ct_get(skb, &ctinfo)) != NULL) { | ||
188 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); | ||
189 | |||
190 | if (!nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.src.u3, | ||
191 | &ct->tuplehash[!dir].tuple.dst.u3) || | ||
192 | (ct->tuplehash[dir].tuple.dst.protonum != IPPROTO_ICMPV6 && | ||
193 | ct->tuplehash[dir].tuple.src.u.all != | ||
194 | ct->tuplehash[!dir].tuple.dst.u.all)) { | ||
195 | err = nf_xfrm_me_harder(skb, AF_INET6); | ||
196 | if (err < 0) | ||
197 | ret = NF_DROP_ERR(err); | ||
198 | } | ||
199 | } | ||
200 | #endif | ||
201 | return ret; | ||
202 | } | 69 | } |
203 | 70 | ||
204 | static unsigned int | 71 | static unsigned int ip6table_nat_local_fn(const struct nf_hook_ops *ops, |
205 | nf_nat_ipv6_local_fn(const struct nf_hook_ops *ops, | 72 | struct sk_buff *skb, |
206 | struct sk_buff *skb, | 73 | const struct net_device *in, |
207 | const struct net_device *in, | 74 | const struct net_device *out, |
208 | const struct net_device *out, | 75 | int (*okfn)(struct sk_buff *)) |
209 | int (*okfn)(struct sk_buff *)) | ||
210 | { | 76 | { |
211 | const struct nf_conn *ct; | 77 | return nf_nat_ipv6_local_fn(ops, skb, in, out, ip6table_nat_do_chain); |
212 | enum ip_conntrack_info ctinfo; | ||
213 | unsigned int ret; | ||
214 | int err; | ||
215 | |||
216 | /* root is playing with raw sockets. */ | ||
217 | if (skb->len < sizeof(struct ipv6hdr)) | ||
218 | return NF_ACCEPT; | ||
219 | |||
220 | ret = nf_nat_ipv6_fn(ops, skb, in, out, okfn); | ||
221 | if (ret != NF_DROP && ret != NF_STOLEN && | ||
222 | (ct = nf_ct_get(skb, &ctinfo)) != NULL) { | ||
223 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); | ||
224 | |||
225 | if (!nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.dst.u3, | ||
226 | &ct->tuplehash[!dir].tuple.src.u3)) { | ||
227 | err = ip6_route_me_harder(skb); | ||
228 | if (err < 0) | ||
229 | ret = NF_DROP_ERR(err); | ||
230 | } | ||
231 | #ifdef CONFIG_XFRM | ||
232 | else if (!(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) && | ||
233 | ct->tuplehash[dir].tuple.dst.protonum != IPPROTO_ICMPV6 && | ||
234 | ct->tuplehash[dir].tuple.dst.u.all != | ||
235 | ct->tuplehash[!dir].tuple.src.u.all) { | ||
236 | err = nf_xfrm_me_harder(skb, AF_INET6); | ||
237 | if (err < 0) | ||
238 | ret = NF_DROP_ERR(err); | ||
239 | } | ||
240 | #endif | ||
241 | } | ||
242 | return ret; | ||
243 | } | 78 | } |
244 | 79 | ||
245 | static struct nf_hook_ops nf_nat_ipv6_ops[] __read_mostly = { | 80 | static struct nf_hook_ops nf_nat_ipv6_ops[] __read_mostly = { |
246 | /* Before packet filtering, change destination */ | 81 | /* Before packet filtering, change destination */ |
247 | { | 82 | { |
248 | .hook = nf_nat_ipv6_in, | 83 | .hook = ip6table_nat_in, |
249 | .owner = THIS_MODULE, | 84 | .owner = THIS_MODULE, |
250 | .pf = NFPROTO_IPV6, | 85 | .pf = NFPROTO_IPV6, |
251 | .hooknum = NF_INET_PRE_ROUTING, | 86 | .hooknum = NF_INET_PRE_ROUTING, |
@@ -253,7 +88,7 @@ static struct nf_hook_ops nf_nat_ipv6_ops[] __read_mostly = { | |||
253 | }, | 88 | }, |
254 | /* After packet filtering, change source */ | 89 | /* After packet filtering, change source */ |
255 | { | 90 | { |
256 | .hook = nf_nat_ipv6_out, | 91 | .hook = ip6table_nat_out, |
257 | .owner = THIS_MODULE, | 92 | .owner = THIS_MODULE, |
258 | .pf = NFPROTO_IPV6, | 93 | .pf = NFPROTO_IPV6, |
259 | .hooknum = NF_INET_POST_ROUTING, | 94 | .hooknum = NF_INET_POST_ROUTING, |
@@ -261,7 +96,7 @@ static struct nf_hook_ops nf_nat_ipv6_ops[] __read_mostly = { | |||
261 | }, | 96 | }, |
262 | /* Before packet filtering, change destination */ | 97 | /* Before packet filtering, change destination */ |
263 | { | 98 | { |
264 | .hook = nf_nat_ipv6_local_fn, | 99 | .hook = ip6table_nat_local_fn, |
265 | .owner = THIS_MODULE, | 100 | .owner = THIS_MODULE, |
266 | .pf = NFPROTO_IPV6, | 101 | .pf = NFPROTO_IPV6, |
267 | .hooknum = NF_INET_LOCAL_OUT, | 102 | .hooknum = NF_INET_LOCAL_OUT, |
@@ -269,7 +104,7 @@ static struct nf_hook_ops nf_nat_ipv6_ops[] __read_mostly = { | |||
269 | }, | 104 | }, |
270 | /* After packet filtering, change source */ | 105 | /* After packet filtering, change source */ |
271 | { | 106 | { |
272 | .hook = nf_nat_ipv6_fn, | 107 | .hook = ip6table_nat_fn, |
273 | .owner = THIS_MODULE, | 108 | .owner = THIS_MODULE, |
274 | .pf = NFPROTO_IPV6, | 109 | .pf = NFPROTO_IPV6, |
275 | .hooknum = NF_INET_LOCAL_IN, | 110 | .hooknum = NF_INET_LOCAL_IN, |
diff --git a/net/ipv6/netfilter/nf_nat_l3proto_ipv6.c b/net/ipv6/netfilter/nf_nat_l3proto_ipv6.c index fc8e49b2ff3e..c5812e1c1ffb 100644 --- a/net/ipv6/netfilter/nf_nat_l3proto_ipv6.c +++ b/net/ipv6/netfilter/nf_nat_l3proto_ipv6.c | |||
@@ -261,6 +261,205 @@ int nf_nat_icmpv6_reply_translation(struct sk_buff *skb, | |||
261 | } | 261 | } |
262 | EXPORT_SYMBOL_GPL(nf_nat_icmpv6_reply_translation); | 262 | EXPORT_SYMBOL_GPL(nf_nat_icmpv6_reply_translation); |
263 | 263 | ||
264 | unsigned int | ||
265 | nf_nat_ipv6_fn(const struct nf_hook_ops *ops, struct sk_buff *skb, | ||
266 | const struct net_device *in, const struct net_device *out, | ||
267 | unsigned int (*do_chain)(const struct nf_hook_ops *ops, | ||
268 | struct sk_buff *skb, | ||
269 | const struct net_device *in, | ||
270 | const struct net_device *out, | ||
271 | struct nf_conn *ct)) | ||
272 | { | ||
273 | struct nf_conn *ct; | ||
274 | enum ip_conntrack_info ctinfo; | ||
275 | struct nf_conn_nat *nat; | ||
276 | enum nf_nat_manip_type maniptype = HOOK2MANIP(ops->hooknum); | ||
277 | __be16 frag_off; | ||
278 | int hdrlen; | ||
279 | u8 nexthdr; | ||
280 | |||
281 | ct = nf_ct_get(skb, &ctinfo); | ||
282 | /* Can't track? It's not due to stress, or conntrack would | ||
283 | * have dropped it. Hence it's the user's responsibilty to | ||
284 | * packet filter it out, or implement conntrack/NAT for that | ||
285 | * protocol. 8) --RR | ||
286 | */ | ||
287 | if (!ct) | ||
288 | return NF_ACCEPT; | ||
289 | |||
290 | /* Don't try to NAT if this packet is not conntracked */ | ||
291 | if (nf_ct_is_untracked(ct)) | ||
292 | return NF_ACCEPT; | ||
293 | |||
294 | nat = nf_ct_nat_ext_add(ct); | ||
295 | if (nat == NULL) | ||
296 | return NF_ACCEPT; | ||
297 | |||
298 | switch (ctinfo) { | ||
299 | case IP_CT_RELATED: | ||
300 | case IP_CT_RELATED_REPLY: | ||
301 | nexthdr = ipv6_hdr(skb)->nexthdr; | ||
302 | hdrlen = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), | ||
303 | &nexthdr, &frag_off); | ||
304 | |||
305 | if (hdrlen >= 0 && nexthdr == IPPROTO_ICMPV6) { | ||
306 | if (!nf_nat_icmpv6_reply_translation(skb, ct, ctinfo, | ||
307 | ops->hooknum, | ||
308 | hdrlen)) | ||
309 | return NF_DROP; | ||
310 | else | ||
311 | return NF_ACCEPT; | ||
312 | } | ||
313 | /* Fall thru... (Only ICMPs can be IP_CT_IS_REPLY) */ | ||
314 | case IP_CT_NEW: | ||
315 | /* Seen it before? This can happen for loopback, retrans, | ||
316 | * or local packets. | ||
317 | */ | ||
318 | if (!nf_nat_initialized(ct, maniptype)) { | ||
319 | unsigned int ret; | ||
320 | |||
321 | ret = do_chain(ops, skb, in, out, ct); | ||
322 | if (ret != NF_ACCEPT) | ||
323 | return ret; | ||
324 | |||
325 | if (nf_nat_initialized(ct, HOOK2MANIP(ops->hooknum))) | ||
326 | break; | ||
327 | |||
328 | ret = nf_nat_alloc_null_binding(ct, ops->hooknum); | ||
329 | if (ret != NF_ACCEPT) | ||
330 | return ret; | ||
331 | } else { | ||
332 | pr_debug("Already setup manip %s for ct %p\n", | ||
333 | maniptype == NF_NAT_MANIP_SRC ? "SRC" : "DST", | ||
334 | ct); | ||
335 | if (nf_nat_oif_changed(ops->hooknum, ctinfo, nat, out)) | ||
336 | goto oif_changed; | ||
337 | } | ||
338 | break; | ||
339 | |||
340 | default: | ||
341 | /* ESTABLISHED */ | ||
342 | NF_CT_ASSERT(ctinfo == IP_CT_ESTABLISHED || | ||
343 | ctinfo == IP_CT_ESTABLISHED_REPLY); | ||
344 | if (nf_nat_oif_changed(ops->hooknum, ctinfo, nat, out)) | ||
345 | goto oif_changed; | ||
346 | } | ||
347 | |||
348 | return nf_nat_packet(ct, ctinfo, ops->hooknum, skb); | ||
349 | |||
350 | oif_changed: | ||
351 | nf_ct_kill_acct(ct, ctinfo, skb); | ||
352 | return NF_DROP; | ||
353 | } | ||
354 | EXPORT_SYMBOL_GPL(nf_nat_ipv6_fn); | ||
355 | |||
356 | unsigned int | ||
357 | nf_nat_ipv6_in(const struct nf_hook_ops *ops, struct sk_buff *skb, | ||
358 | const struct net_device *in, const struct net_device *out, | ||
359 | unsigned int (*do_chain)(const struct nf_hook_ops *ops, | ||
360 | struct sk_buff *skb, | ||
361 | const struct net_device *in, | ||
362 | const struct net_device *out, | ||
363 | struct nf_conn *ct)) | ||
364 | { | ||
365 | unsigned int ret; | ||
366 | struct in6_addr daddr = ipv6_hdr(skb)->daddr; | ||
367 | |||
368 | ret = nf_nat_ipv6_fn(ops, skb, in, out, do_chain); | ||
369 | if (ret != NF_DROP && ret != NF_STOLEN && | ||
370 | ipv6_addr_cmp(&daddr, &ipv6_hdr(skb)->daddr)) | ||
371 | skb_dst_drop(skb); | ||
372 | |||
373 | return ret; | ||
374 | } | ||
375 | EXPORT_SYMBOL_GPL(nf_nat_ipv6_in); | ||
376 | |||
377 | unsigned int | ||
378 | nf_nat_ipv6_out(const struct nf_hook_ops *ops, struct sk_buff *skb, | ||
379 | const struct net_device *in, const struct net_device *out, | ||
380 | unsigned int (*do_chain)(const struct nf_hook_ops *ops, | ||
381 | struct sk_buff *skb, | ||
382 | const struct net_device *in, | ||
383 | const struct net_device *out, | ||
384 | struct nf_conn *ct)) | ||
385 | { | ||
386 | #ifdef CONFIG_XFRM | ||
387 | const struct nf_conn *ct; | ||
388 | enum ip_conntrack_info ctinfo; | ||
389 | int err; | ||
390 | #endif | ||
391 | unsigned int ret; | ||
392 | |||
393 | /* root is playing with raw sockets. */ | ||
394 | if (skb->len < sizeof(struct ipv6hdr)) | ||
395 | return NF_ACCEPT; | ||
396 | |||
397 | ret = nf_nat_ipv6_fn(ops, skb, in, out, do_chain); | ||
398 | #ifdef CONFIG_XFRM | ||
399 | if (ret != NF_DROP && ret != NF_STOLEN && | ||
400 | !(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) && | ||
401 | (ct = nf_ct_get(skb, &ctinfo)) != NULL) { | ||
402 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); | ||
403 | |||
404 | if (!nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.src.u3, | ||
405 | &ct->tuplehash[!dir].tuple.dst.u3) || | ||
406 | (ct->tuplehash[dir].tuple.dst.protonum != IPPROTO_ICMPV6 && | ||
407 | ct->tuplehash[dir].tuple.src.u.all != | ||
408 | ct->tuplehash[!dir].tuple.dst.u.all)) { | ||
409 | err = nf_xfrm_me_harder(skb, AF_INET6); | ||
410 | if (err < 0) | ||
411 | ret = NF_DROP_ERR(err); | ||
412 | } | ||
413 | } | ||
414 | #endif | ||
415 | return ret; | ||
416 | } | ||
417 | EXPORT_SYMBOL_GPL(nf_nat_ipv6_out); | ||
418 | |||
419 | unsigned int | ||
420 | nf_nat_ipv6_local_fn(const struct nf_hook_ops *ops, struct sk_buff *skb, | ||
421 | const struct net_device *in, const struct net_device *out, | ||
422 | unsigned int (*do_chain)(const struct nf_hook_ops *ops, | ||
423 | struct sk_buff *skb, | ||
424 | const struct net_device *in, | ||
425 | const struct net_device *out, | ||
426 | struct nf_conn *ct)) | ||
427 | { | ||
428 | const struct nf_conn *ct; | ||
429 | enum ip_conntrack_info ctinfo; | ||
430 | unsigned int ret; | ||
431 | int err; | ||
432 | |||
433 | /* root is playing with raw sockets. */ | ||
434 | if (skb->len < sizeof(struct ipv6hdr)) | ||
435 | return NF_ACCEPT; | ||
436 | |||
437 | ret = nf_nat_ipv6_fn(ops, skb, in, out, do_chain); | ||
438 | if (ret != NF_DROP && ret != NF_STOLEN && | ||
439 | (ct = nf_ct_get(skb, &ctinfo)) != NULL) { | ||
440 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); | ||
441 | |||
442 | if (!nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.dst.u3, | ||
443 | &ct->tuplehash[!dir].tuple.src.u3)) { | ||
444 | err = ip6_route_me_harder(skb); | ||
445 | if (err < 0) | ||
446 | ret = NF_DROP_ERR(err); | ||
447 | } | ||
448 | #ifdef CONFIG_XFRM | ||
449 | else if (!(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) && | ||
450 | ct->tuplehash[dir].tuple.dst.protonum != IPPROTO_ICMPV6 && | ||
451 | ct->tuplehash[dir].tuple.dst.u.all != | ||
452 | ct->tuplehash[!dir].tuple.src.u.all) { | ||
453 | err = nf_xfrm_me_harder(skb, AF_INET6); | ||
454 | if (err < 0) | ||
455 | ret = NF_DROP_ERR(err); | ||
456 | } | ||
457 | #endif | ||
458 | } | ||
459 | return ret; | ||
460 | } | ||
461 | EXPORT_SYMBOL_GPL(nf_nat_ipv6_local_fn); | ||
462 | |||
264 | static int __init nf_nat_l3proto_ipv6_init(void) | 463 | static int __init nf_nat_l3proto_ipv6_init(void) |
265 | { | 464 | { |
266 | int err; | 465 | int err; |
diff --git a/net/ipv6/netfilter/nft_chain_nat_ipv6.c b/net/ipv6/netfilter/nft_chain_nat_ipv6.c index d189fcb437fe..c1c74491a10b 100644 --- a/net/ipv6/netfilter/nft_chain_nat_ipv6.c +++ b/net/ipv6/netfilter/nft_chain_nat_ipv6.c | |||
@@ -28,7 +28,7 @@ | |||
28 | * IPv6 NAT chains | 28 | * IPv6 NAT chains |
29 | */ | 29 | */ |
30 | 30 | ||
31 | static unsigned int nf_nat_ipv6_fn(const struct nf_hook_ops *ops, | 31 | static unsigned int nft_nat_ipv6_fn(const struct nf_hook_ops *ops, |
32 | struct sk_buff *skb, | 32 | struct sk_buff *skb, |
33 | const struct net_device *in, | 33 | const struct net_device *in, |
34 | const struct net_device *out, | 34 | const struct net_device *out, |
@@ -97,7 +97,7 @@ static unsigned int nf_nat_ipv6_prerouting(const struct nf_hook_ops *ops, | |||
97 | struct in6_addr daddr = ipv6_hdr(skb)->daddr; | 97 | struct in6_addr daddr = ipv6_hdr(skb)->daddr; |
98 | unsigned int ret; | 98 | unsigned int ret; |
99 | 99 | ||
100 | ret = nf_nat_ipv6_fn(ops, skb, in, out, okfn); | 100 | ret = nft_nat_ipv6_fn(ops, skb, in, out, okfn); |
101 | if (ret != NF_DROP && ret != NF_STOLEN && | 101 | if (ret != NF_DROP && ret != NF_STOLEN && |
102 | ipv6_addr_cmp(&daddr, &ipv6_hdr(skb)->daddr)) | 102 | ipv6_addr_cmp(&daddr, &ipv6_hdr(skb)->daddr)) |
103 | skb_dst_drop(skb); | 103 | skb_dst_drop(skb); |
@@ -115,7 +115,7 @@ static unsigned int nf_nat_ipv6_postrouting(const struct nf_hook_ops *ops, | |||
115 | const struct nf_conn *ct __maybe_unused; | 115 | const struct nf_conn *ct __maybe_unused; |
116 | unsigned int ret; | 116 | unsigned int ret; |
117 | 117 | ||
118 | ret = nf_nat_ipv6_fn(ops, skb, in, out, okfn); | 118 | ret = nft_nat_ipv6_fn(ops, skb, in, out, okfn); |
119 | #ifdef CONFIG_XFRM | 119 | #ifdef CONFIG_XFRM |
120 | if (ret != NF_DROP && ret != NF_STOLEN && | 120 | if (ret != NF_DROP && ret != NF_STOLEN && |
121 | !(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) && | 121 | !(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) && |
@@ -143,7 +143,7 @@ static unsigned int nf_nat_ipv6_output(const struct nf_hook_ops *ops, | |||
143 | const struct nf_conn *ct; | 143 | const struct nf_conn *ct; |
144 | unsigned int ret; | 144 | unsigned int ret; |
145 | 145 | ||
146 | ret = nf_nat_ipv6_fn(ops, skb, in, out, okfn); | 146 | ret = nft_nat_ipv6_fn(ops, skb, in, out, okfn); |
147 | if (ret != NF_DROP && ret != NF_STOLEN && | 147 | if (ret != NF_DROP && ret != NF_STOLEN && |
148 | (ct = nf_ct_get(skb, &ctinfo)) != NULL) { | 148 | (ct = nf_ct_get(skb, &ctinfo)) != NULL) { |
149 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); | 149 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); |
@@ -177,7 +177,7 @@ static const struct nf_chain_type nft_chain_nat_ipv6 = { | |||
177 | [NF_INET_PRE_ROUTING] = nf_nat_ipv6_prerouting, | 177 | [NF_INET_PRE_ROUTING] = nf_nat_ipv6_prerouting, |
178 | [NF_INET_POST_ROUTING] = nf_nat_ipv6_postrouting, | 178 | [NF_INET_POST_ROUTING] = nf_nat_ipv6_postrouting, |
179 | [NF_INET_LOCAL_OUT] = nf_nat_ipv6_output, | 179 | [NF_INET_LOCAL_OUT] = nf_nat_ipv6_output, |
180 | [NF_INET_LOCAL_IN] = nf_nat_ipv6_fn, | 180 | [NF_INET_LOCAL_IN] = nft_nat_ipv6_fn, |
181 | }, | 181 | }, |
182 | }; | 182 | }; |
183 | 183 | ||