NPF: fix the recent breakage of the traceroute ALG. Also, simplify and refactor a little bit.diff -r1.19 -r1.20 src/sys/net/npf/npf_alg_icmp.c
(rmind)
--- src/sys/net/npf/npf_alg_icmp.c 2014/02/16 22:10:40 1.19
+++ src/sys/net/npf/npf_alg_icmp.c 2014/02/19 03:51:31 1.20
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: npf_alg_icmp.c,v 1.19 2014/02/16 22:10:40 rmind Exp $ */ | 1 | /* $NetBSD: npf_alg_icmp.c,v 1.20 2014/02/19 03:51:31 rmind Exp $ */ | |
2 | 2 | |||
3 | /*- | 3 | /*- | |
4 | * Copyright (c) 2010 The NetBSD Foundation, Inc. | 4 | * Copyright (c) 2010 The NetBSD Foundation, Inc. | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * This material is based upon work partially supported by The | 7 | * This material is based upon work partially supported by The | |
8 | * NetBSD Foundation under a contract with Mindaugas Rasiukevicius. | 8 | * NetBSD Foundation under a contract with Mindaugas Rasiukevicius. | |
9 | * | 9 | * | |
10 | * Redistribution and use in source and binary forms, with or without | 10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions | 11 | * modification, are permitted provided that the following conditions | |
12 | * are met: | 12 | * are met: | |
13 | * 1. Redistributions of source code must retain the above copyright | 13 | * 1. Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | 14 | * notice, this list of conditions and the following disclaimer. | |
@@ -24,27 +24,27 @@ | @@ -24,27 +24,27 @@ | |||
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
29 | * POSSIBILITY OF SUCH DAMAGE. | 29 | * POSSIBILITY OF SUCH DAMAGE. | |
30 | */ | 30 | */ | |
31 | 31 | |||
32 | /* | 32 | /* | |
33 | * NPF ALG for ICMP and traceroute translations. | 33 | * NPF ALG for ICMP and traceroute translations. | |
34 | */ | 34 | */ | |
35 | 35 | |||
36 | #include <sys/cdefs.h> | 36 | #include <sys/cdefs.h> | |
37 | __KERNEL_RCSID(0, "$NetBSD: npf_alg_icmp.c,v 1.19 2014/02/16 22:10:40 rmind Exp $"); | 37 | __KERNEL_RCSID(0, "$NetBSD: npf_alg_icmp.c,v 1.20 2014/02/19 03:51:31 rmind Exp $"); | |
38 | 38 | |||
39 | #include <sys/param.h> | 39 | #include <sys/param.h> | |
40 | #include <sys/module.h> | 40 | #include <sys/module.h> | |
41 | 41 | |||
42 | #include <netinet/in_systm.h> | 42 | #include <netinet/in_systm.h> | |
43 | #include <netinet/in.h> | 43 | #include <netinet/in.h> | |
44 | #include <netinet/ip.h> | 44 | #include <netinet/ip.h> | |
45 | #include <netinet/tcp.h> | 45 | #include <netinet/tcp.h> | |
46 | #include <netinet/udp.h> | 46 | #include <netinet/udp.h> | |
47 | #include <netinet/ip_icmp.h> | 47 | #include <netinet/ip_icmp.h> | |
48 | #include <netinet/icmp6.h> | 48 | #include <netinet/icmp6.h> | |
49 | #include <net/pfil.h> | 49 | #include <net/pfil.h> | |
50 | 50 | |||
@@ -295,95 +295,102 @@ npfa_icmp_session(npf_cache_t *npc, nbuf | @@ -295,95 +295,102 @@ npfa_icmp_session(npf_cache_t *npc, nbuf | |||
295 | } | 295 | } | |
296 | 296 | |||
297 | /* Lookup for a session using embedded packet. */ | 297 | /* Lookup for a session using embedded packet. */ | |
298 | return npf_session_lookup(&enpc, nbuf, di, &forw); | 298 | return npf_session_lookup(&enpc, nbuf, di, &forw); | |
299 | } | 299 | } | |
300 | 300 | |||
301 | /* | 301 | /* | |
302 | * npfa_icmp_nat: ALG translator - rewrites IP address in the IP header | 302 | * npfa_icmp_nat: ALG translator - rewrites IP address in the IP header | |
303 | * which is embedded in ICMP packet. Note: backwards stream only. | 303 | * which is embedded in ICMP packet. Note: backwards stream only. | |
304 | */ | 304 | */ | |
305 | static bool | 305 | static bool | |
306 | npfa_icmp_nat(npf_cache_t *npc, nbuf_t *nbuf, npf_nat_t *nt, bool forw) | 306 | npfa_icmp_nat(npf_cache_t *npc, nbuf_t *nbuf, npf_nat_t *nt, bool forw) | |
307 | { | 307 | { | |
308 | const u_int which = NPF_SRC; | |||
308 | npf_cache_t enpc; | 309 | npf_cache_t enpc; | |
309 | 310 | |||
310 | if (forw || !npf_iscached(npc, NPC_ICMP)) | 311 | if (forw || !npf_iscached(npc, NPC_ICMP)) | |
311 | return false; | 312 | return false; | |
312 | if (!npfa_icmp_inspect(npc, nbuf, &enpc)) | 313 | if (!npfa_icmp_inspect(npc, nbuf, &enpc)) | |
313 | return false; | 314 | return false; | |
314 | 315 | |||
315 | KASSERT(npf_iscached(&enpc, NPC_IP46)); | 316 | KASSERT(npf_iscached(&enpc, NPC_IP46)); | |
316 | KASSERT(npf_iscached(&enpc, NPC_LAYER4)); | 317 | KASSERT(npf_iscached(&enpc, NPC_LAYER4)); | |
317 | 318 | |||
319 | /* | |||
320 | * ICMP: fetch the current checksum we are going to fixup. | |||
321 | */ | |||
318 | struct icmp *ic = npc->npc_l4.icmp; | 322 | struct icmp *ic = npc->npc_l4.icmp; | |
319 | uint16_t cksum = ic->icmp_cksum; | 323 | uint16_t cksum = ic->icmp_cksum; | |
320 | 324 | |||
321 | CTASSERT(offsetof(struct icmp, icmp_cksum) == | 325 | CTASSERT(offsetof(struct icmp, icmp_cksum) == | |
322 | offsetof(struct icmp6_hdr, icmp6_cksum)); | 326 | offsetof(struct icmp6_hdr, icmp6_cksum)); | |
323 | 327 | |||
324 | /* | 328 | /* | |
325 | * Retrieve the original address and port, then calculate ICMP | 329 | * Fetch the IP and port in the _embedded_ packet. Also, fetch | |
326 | * checksum for these changes in the embedded packet. While data | 330 | * the IPv4 and TCP/UDP checksums before they are rewritten. | |
327 | * is not rewritten in the cache, save IP and TCP/UDP checksums. | 331 | * Calculate the part of the ICMP checksum fixup. | |
328 | * | |||
329 | * XXX: Assumes NPF_NATOUT (source address/port). Currently, | |||
330 | * npfa_icmp_match() matches only for the PFIL_OUT traffic. | |||
331 | */ | 332 | */ | |
332 | const int proto = enpc.npc_proto; | 333 | const int proto = enpc.npc_proto; | |
333 | uint16_t ipcksum = 0, l4cksum = 0; | 334 | uint16_t ipcksum = 0, l4cksum = 0; | |
334 | npf_addr_t *addr; | 335 | npf_addr_t *addr; | |
335 | in_port_t port; | 336 | in_port_t port; | |
336 | 337 | |||
337 | npf_nat_getorig(nt, &addr, &port); | 338 | npf_nat_getorig(nt, &addr, &port); | |
338 | 339 | |||
339 | if (npf_iscached(&enpc, NPC_IP4)) { | 340 | if (npf_iscached(&enpc, NPC_IP4)) { | |
340 | const struct ip *eip = enpc.npc_ip.v4; | 341 | const struct ip *eip = enpc.npc_ip.v4; | |
341 | ipcksum = eip->ip_sum; | 342 | ipcksum = eip->ip_sum; | |
342 | } | 343 | } | |
343 | cksum = npf_addr_cksum(cksum, enpc.npc_alen, enpc.npc_ips[NPF_SRC], addr); | 344 | cksum = npf_addr_cksum(cksum, enpc.npc_alen, enpc.npc_ips[which], addr); | |
344 | 345 | |||
345 | switch (proto) { | 346 | switch (proto) { | |
346 | case IPPROTO_TCP: { | 347 | case IPPROTO_TCP: { | |
347 | const struct tcphdr *th = enpc.npc_l4.tcp; | 348 | const struct tcphdr *th = enpc.npc_l4.tcp; | |
348 | cksum = npf_fixup16_cksum(cksum, th->th_sport, port); | 349 | cksum = npf_fixup16_cksum(cksum, th->th_sport, port); | |
349 | l4cksum = th->th_sum; | 350 | l4cksum = th->th_sum; | |
350 | break; | 351 | break; | |
351 | } | 352 | } | |
352 | case IPPROTO_UDP: { | 353 | case IPPROTO_UDP: { | |
353 | const struct udphdr *uh = enpc.npc_l4.udp; | 354 | const struct udphdr *uh = enpc.npc_l4.udp; | |
354 | cksum = npf_fixup16_cksum(cksum, uh->uh_sport, port); | 355 | cksum = npf_fixup16_cksum(cksum, uh->uh_sport, port); | |
355 | l4cksum = uh->uh_sum; | 356 | l4cksum = uh->uh_sum; | |
356 | break; | 357 | break; | |
357 | } | 358 | } | |
358 | case IPPROTO_ICMP: | 359 | case IPPROTO_ICMP: | |
359 | case IPPROTO_ICMPV6: | 360 | case IPPROTO_ICMPV6: | |
360 | break; | 361 | break; | |
361 | default: | 362 | default: | |
362 | return false; | 363 | return false; | |
363 | } | 364 | } | |
364 | 365 | |||
365 | /* | 366 | /* | |
366 | * Rewrite the source IP address and port of the embedded IP header, | 367 | * Translate the embedded packet. The following changes will | |
367 | * which represents the original packet. This updates the checksums | 368 | * be performed by npf_napt_rwr(): | |
368 | * in the embedded packet. | 369 | * | |
370 | * 1) Rewrite the IP address and, if not ICMP, port. | |||
371 | * 2) Rewrite the TCP/UDP checksum (if not ICMP). | |||
372 | * 3) Rewrite the IPv4 checksum for (1) and (2). | |||
373 | * | |||
374 | * XXX: Assumes NPF_NATOUT (source address/port). Currently, | |||
375 | * npfa_icmp_match() matches only for the PFIL_OUT traffic. | |||
369 | */ | 376 | */ | |
370 | if (npf_nat_translate(&enpc, nbuf, nt, forw)) { | 377 | if (npf_napt_rwr(&enpc, which, addr, port)) { | |
371 | return false; | 378 | return false; | |
372 | } | 379 | } | |
373 | 380 | |||
374 | /* | 381 | /* | |
375 | * Finish calculation of the ICMP checksum: include the checksum | 382 | * Finally, finish the ICMP checksum fixup: include the checksum | |
376 | * change in the embedded packet. | 383 | * changes in the embedded packet. | |
377 | */ | 384 | */ | |
378 | if (npf_iscached(&enpc, NPC_IP4)) { | 385 | if (npf_iscached(&enpc, NPC_IP4)) { | |
379 | const struct ip *eip = enpc.npc_ip.v4; | 386 | const struct ip *eip = enpc.npc_ip.v4; | |
380 | cksum = npf_fixup16_cksum(cksum, ipcksum, eip->ip_sum); | 387 | cksum = npf_fixup16_cksum(cksum, ipcksum, eip->ip_sum); | |
381 | } | 388 | } | |
382 | switch (proto) { | 389 | switch (proto) { | |
383 | case IPPROTO_TCP: { | 390 | case IPPROTO_TCP: { | |
384 | const struct tcphdr *th = enpc.npc_l4.tcp; | 391 | const struct tcphdr *th = enpc.npc_l4.tcp; | |
385 | cksum = npf_fixup16_cksum(cksum, l4cksum, th->th_sum); | 392 | cksum = npf_fixup16_cksum(cksum, l4cksum, th->th_sum); | |
386 | break; | 393 | break; | |
387 | } | 394 | } | |
388 | case IPPROTO_UDP: | 395 | case IPPROTO_UDP: | |
389 | if (l4cksum) { | 396 | if (l4cksum) { |
--- src/sys/net/npf/npf_impl.h 2014/02/16 22:10:40 1.48
+++ src/sys/net/npf/npf_impl.h 2014/02/19 03:51:31 1.49
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: npf_impl.h,v 1.48 2014/02/16 22:10:40 rmind Exp $ */ | 1 | /* $NetBSD: npf_impl.h,v 1.49 2014/02/19 03:51:31 rmind Exp $ */ | |
2 | 2 | |||
3 | /*- | 3 | /*- | |
4 | * Copyright (c) 2009-2014 The NetBSD Foundation, Inc. | 4 | * Copyright (c) 2009-2014 The NetBSD Foundation, Inc. | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * This material is based upon work partially supported by The | 7 | * This material is based upon work partially supported by The | |
8 | * NetBSD Foundation under a contract with Mindaugas Rasiukevicius. | 8 | * NetBSD Foundation under a contract with Mindaugas Rasiukevicius. | |
9 | * | 9 | * | |
10 | * Redistribution and use in source and binary forms, with or without | 10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions | 11 | * modification, are permitted provided that the following conditions | |
12 | * are met: | 12 | * are met: | |
13 | * 1. Redistributions of source code must retain the above copyright | 13 | * 1. Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | 14 | * notice, this list of conditions and the following disclaimer. | |
@@ -190,26 +190,28 @@ u_int npf_ifmap_id(const ifnet_t *); | @@ -190,26 +190,28 @@ u_int npf_ifmap_id(const ifnet_t *); | |||
190 | int npf_pfil_register(bool); | 190 | int npf_pfil_register(bool); | |
191 | void npf_pfil_unregister(bool); | 191 | void npf_pfil_unregister(bool); | |
192 | bool npf_pfil_registered_p(void); | 192 | bool npf_pfil_registered_p(void); | |
193 | int npf_packet_handler(void *, struct mbuf **, ifnet_t *, int); | 193 | int npf_packet_handler(void *, struct mbuf **, ifnet_t *, int); | |
194 | 194 | |||
195 | /* Protocol helpers. */ | 195 | /* Protocol helpers. */ | |
196 | int npf_cache_all(npf_cache_t *, nbuf_t *); | 196 | int npf_cache_all(npf_cache_t *, nbuf_t *); | |
197 | void npf_recache(npf_cache_t *, nbuf_t *); | 197 | void npf_recache(npf_cache_t *, nbuf_t *); | |
198 | 198 | |||
199 | bool npf_rwrip(const npf_cache_t *, u_int, const npf_addr_t *); | 199 | bool npf_rwrip(const npf_cache_t *, u_int, const npf_addr_t *); | |
200 | bool npf_rwrport(const npf_cache_t *, u_int, const in_port_t); | 200 | bool npf_rwrport(const npf_cache_t *, u_int, const in_port_t); | |
201 | bool npf_rwrcksum(const npf_cache_t *, u_int, | 201 | bool npf_rwrcksum(const npf_cache_t *, u_int, | |
202 | const npf_addr_t *, const in_port_t); | 202 | const npf_addr_t *, const in_port_t); | |
203 | int npf_napt_rwr(const npf_cache_t *, u_int, const npf_addr_t *, | |||
204 | const in_addr_t); | |||
203 | int npf_npt66_rwr(const npf_cache_t *, u_int, const npf_addr_t *, | 205 | int npf_npt66_rwr(const npf_cache_t *, u_int, const npf_addr_t *, | |
204 | npf_netmask_t, uint16_t); | 206 | npf_netmask_t, uint16_t); | |
205 | 207 | |||
206 | uint16_t npf_fixup16_cksum(uint16_t, uint16_t, uint16_t); | 208 | uint16_t npf_fixup16_cksum(uint16_t, uint16_t, uint16_t); | |
207 | uint16_t npf_fixup32_cksum(uint16_t, uint32_t, uint32_t); | 209 | uint16_t npf_fixup32_cksum(uint16_t, uint32_t, uint32_t); | |
208 | uint16_t npf_addr_cksum(uint16_t, int, const npf_addr_t *, | 210 | uint16_t npf_addr_cksum(uint16_t, int, const npf_addr_t *, | |
209 | const npf_addr_t *); | 211 | const npf_addr_t *); | |
210 | uint32_t npf_addr_mix(const int, const npf_addr_t *, const npf_addr_t *); | 212 | uint32_t npf_addr_mix(const int, const npf_addr_t *, const npf_addr_t *); | |
211 | int npf_addr_cmp(const npf_addr_t *, const npf_netmask_t, | 213 | int npf_addr_cmp(const npf_addr_t *, const npf_netmask_t, | |
212 | const npf_addr_t *, const npf_netmask_t, const int); | 214 | const npf_addr_t *, const npf_netmask_t, const int); | |
213 | void npf_addr_mask(const npf_addr_t *, const npf_netmask_t, | 215 | void npf_addr_mask(const npf_addr_t *, const npf_netmask_t, | |
214 | const int, npf_addr_t *); | 216 | const int, npf_addr_t *); | |
215 | 217 | |||
@@ -331,27 +333,26 @@ void npf_state_destroy(npf_state_t *); | @@ -331,27 +333,26 @@ void npf_state_destroy(npf_state_t *); | |||
331 | bool npf_state_tcp(npf_cache_t *, nbuf_t *, npf_state_t *, int); | 333 | bool npf_state_tcp(npf_cache_t *, nbuf_t *, npf_state_t *, int); | |
332 | int npf_state_tcp_timeout(const npf_state_t *); | 334 | int npf_state_tcp_timeout(const npf_state_t *); | |
333 | 335 | |||
334 | /* NAT. */ | 336 | /* NAT. */ | |
335 | void npf_nat_sysinit(void); | 337 | void npf_nat_sysinit(void); | |
336 | void npf_nat_sysfini(void); | 338 | void npf_nat_sysfini(void); | |
337 | npf_natpolicy_t *npf_nat_newpolicy(prop_dictionary_t, npf_ruleset_t *); | 339 | npf_natpolicy_t *npf_nat_newpolicy(prop_dictionary_t, npf_ruleset_t *); | |
338 | void npf_nat_freepolicy(npf_natpolicy_t *); | 340 | void npf_nat_freepolicy(npf_natpolicy_t *); | |
339 | bool npf_nat_matchpolicy(npf_natpolicy_t *, npf_natpolicy_t *); | 341 | bool npf_nat_matchpolicy(npf_natpolicy_t *, npf_natpolicy_t *); | |
340 | bool npf_nat_sharepm(npf_natpolicy_t *, npf_natpolicy_t *); | 342 | bool npf_nat_sharepm(npf_natpolicy_t *, npf_natpolicy_t *); | |
341 | void npf_nat_freealg(npf_natpolicy_t *, npf_alg_t *); | 343 | void npf_nat_freealg(npf_natpolicy_t *, npf_alg_t *); | |
342 | 344 | |||
343 | int npf_do_nat(npf_cache_t *, npf_session_t *, nbuf_t *, const int); | 345 | int npf_do_nat(npf_cache_t *, npf_session_t *, nbuf_t *, const int); | |
344 | int npf_nat_translate(npf_cache_t *, nbuf_t *, npf_nat_t *, bool); | |||
345 | void npf_nat_destroy(npf_nat_t *); | 346 | void npf_nat_destroy(npf_nat_t *); | |
346 | void npf_nat_getorig(npf_nat_t *, npf_addr_t **, in_port_t *); | 347 | void npf_nat_getorig(npf_nat_t *, npf_addr_t **, in_port_t *); | |
347 | void npf_nat_gettrans(npf_nat_t *, npf_addr_t **, in_port_t *); | 348 | void npf_nat_gettrans(npf_nat_t *, npf_addr_t **, in_port_t *); | |
348 | void npf_nat_setalg(npf_nat_t *, npf_alg_t *, uintptr_t); | 349 | void npf_nat_setalg(npf_nat_t *, npf_alg_t *, uintptr_t); | |
349 | 350 | |||
350 | int npf_nat_save(prop_dictionary_t, prop_array_t, npf_nat_t *); | 351 | int npf_nat_save(prop_dictionary_t, prop_array_t, npf_nat_t *); | |
351 | npf_nat_t * npf_nat_restore(prop_dictionary_t, npf_session_t *); | 352 | npf_nat_t * npf_nat_restore(prop_dictionary_t, npf_session_t *); | |
352 | 353 | |||
353 | /* ALG interface. */ | 354 | /* ALG interface. */ | |
354 | void npf_alg_sysinit(void); | 355 | void npf_alg_sysinit(void); | |
355 | void npf_alg_sysfini(void); | 356 | void npf_alg_sysfini(void); | |
356 | npf_alg_t * npf_alg_register(const char *, const npfa_funcs_t *); | 357 | npf_alg_t * npf_alg_register(const char *, const npfa_funcs_t *); | |
357 | int npf_alg_unregister(npf_alg_t *); | 358 | int npf_alg_unregister(npf_alg_t *); |
--- src/sys/net/npf/npf_inet.c 2014/02/13 03:34:40 1.29
+++ src/sys/net/npf/npf_inet.c 2014/02/19 03:51:31 1.30
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: npf_inet.c,v 1.29 2014/02/13 03:34:40 rmind Exp $ */ | 1 | /* $NetBSD: npf_inet.c,v 1.30 2014/02/19 03:51:31 rmind Exp $ */ | |
2 | 2 | |||
3 | /*- | 3 | /*- | |
4 | * Copyright (c) 2009-2014 The NetBSD Foundation, Inc. | 4 | * Copyright (c) 2009-2014 The NetBSD Foundation, Inc. | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * This material is based upon work partially supported by The | 7 | * This material is based upon work partially supported by The | |
8 | * NetBSD Foundation under a contract with Mindaugas Rasiukevicius. | 8 | * NetBSD Foundation under a contract with Mindaugas Rasiukevicius. | |
9 | * | 9 | * | |
10 | * Redistribution and use in source and binary forms, with or without | 10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions | 11 | * modification, are permitted provided that the following conditions | |
12 | * are met: | 12 | * are met: | |
13 | * 1. Redistributions of source code must retain the above copyright | 13 | * 1. Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | 14 | * notice, this list of conditions and the following disclaimer. | |
@@ -29,27 +29,27 @@ | @@ -29,27 +29,27 @@ | |||
29 | * POSSIBILITY OF SUCH DAMAGE. | 29 | * POSSIBILITY OF SUCH DAMAGE. | |
30 | */ | 30 | */ | |
31 | 31 | |||
32 | /* | 32 | /* | |
33 | * Various protocol related helper routines. | 33 | * Various protocol related helper routines. | |
34 | * | 34 | * | |
35 | * This layer manipulates npf_cache_t structure i.e. caches requested headers | 35 | * This layer manipulates npf_cache_t structure i.e. caches requested headers | |
36 | * and stores which information was cached in the information bit field. | 36 | * and stores which information was cached in the information bit field. | |
37 | * It is also responsibility of this layer to update or invalidate the cache | 37 | * It is also responsibility of this layer to update or invalidate the cache | |
38 | * on rewrites (e.g. by translation routines). | 38 | * on rewrites (e.g. by translation routines). | |
39 | */ | 39 | */ | |
40 | 40 | |||
41 | #include <sys/cdefs.h> | 41 | #include <sys/cdefs.h> | |
42 | __KERNEL_RCSID(0, "$NetBSD: npf_inet.c,v 1.29 2014/02/13 03:34:40 rmind Exp $"); | 42 | __KERNEL_RCSID(0, "$NetBSD: npf_inet.c,v 1.30 2014/02/19 03:51:31 rmind Exp $"); | |
43 | 43 | |||
44 | #include <sys/param.h> | 44 | #include <sys/param.h> | |
45 | #include <sys/types.h> | 45 | #include <sys/types.h> | |
46 | 46 | |||
47 | #include <net/pfil.h> | 47 | #include <net/pfil.h> | |
48 | #include <net/if.h> | 48 | #include <net/if.h> | |
49 | #include <net/ethertypes.h> | 49 | #include <net/ethertypes.h> | |
50 | #include <net/if_ether.h> | 50 | #include <net/if_ether.h> | |
51 | 51 | |||
52 | #include <netinet/in_systm.h> | 52 | #include <netinet/in_systm.h> | |
53 | #include <netinet/in.h> | 53 | #include <netinet/in.h> | |
54 | #include <netinet/ip.h> | 54 | #include <netinet/ip.h> | |
55 | #include <netinet/ip6.h> | 55 | #include <netinet/ip6.h> | |
@@ -568,27 +568,27 @@ npf_rwrcksum(const npf_cache_t *npc, u_i | @@ -568,27 +568,27 @@ npf_rwrcksum(const npf_cache_t *npc, u_i | |||
568 | 568 | |||
569 | if (npf_iscached(npc, NPC_IP4)) { | 569 | if (npf_iscached(npc, NPC_IP4)) { | |
570 | struct ip *ip = npc->npc_ip.v4; | 570 | struct ip *ip = npc->npc_ip.v4; | |
571 | uint16_t ipsum = ip->ip_sum; | 571 | uint16_t ipsum = ip->ip_sum; | |
572 | 572 | |||
573 | /* Recalculate IPv4 checksum and rewrite. */ | 573 | /* Recalculate IPv4 checksum and rewrite. */ | |
574 | ip->ip_sum = npf_addr_cksum(ipsum, alen, oaddr, addr); | 574 | ip->ip_sum = npf_addr_cksum(ipsum, alen, oaddr, addr); | |
575 | } else { | 575 | } else { | |
576 | /* No checksum for IPv6. */ | 576 | /* No checksum for IPv6. */ | |
577 | KASSERT(npf_iscached(npc, NPC_IP6)); | 577 | KASSERT(npf_iscached(npc, NPC_IP6)); | |
578 | } | 578 | } | |
579 | 579 | |||
580 | /* Nothing else to do for ICMP. */ | 580 | /* Nothing else to do for ICMP. */ | |
581 | if (proto == IPPROTO_ICMP) { | 581 | if (proto == IPPROTO_ICMP || proto == IPPROTO_ICMPV6) { | |
582 | return true; | 582 | return true; | |
583 | } | 583 | } | |
584 | KASSERT(npf_iscached(npc, NPC_TCP) || npf_iscached(npc, NPC_UDP)); | 584 | KASSERT(npf_iscached(npc, NPC_TCP) || npf_iscached(npc, NPC_UDP)); | |
585 | 585 | |||
586 | /* | 586 | /* | |
587 | * Calculate TCP/UDP checksum: | 587 | * Calculate TCP/UDP checksum: | |
588 | * - Skip if UDP and the current checksum is zero. | 588 | * - Skip if UDP and the current checksum is zero. | |
589 | * - Fixup the IP address change. | 589 | * - Fixup the IP address change. | |
590 | * - Fixup the port change, if required (non-zero). | 590 | * - Fixup the port change, if required (non-zero). | |
591 | */ | 591 | */ | |
592 | if (proto == IPPROTO_TCP) { | 592 | if (proto == IPPROTO_TCP) { | |
593 | struct tcphdr *th = npc->npc_l4.tcp; | 593 | struct tcphdr *th = npc->npc_l4.tcp; | |
594 | 594 | |||
@@ -607,26 +607,70 @@ npf_rwrcksum(const npf_cache_t *npc, u_i | @@ -607,26 +607,70 @@ npf_rwrcksum(const npf_cache_t *npc, u_i | |||
607 | } | 607 | } | |
608 | 608 | |||
609 | uint16_t cksum = npf_addr_cksum(*ocksum, alen, oaddr, addr); | 609 | uint16_t cksum = npf_addr_cksum(*ocksum, alen, oaddr, addr); | |
610 | if (port) { | 610 | if (port) { | |
611 | cksum = npf_fixup16_cksum(cksum, oport, port); | 611 | cksum = npf_fixup16_cksum(cksum, oport, port); | |
612 | } | 612 | } | |
613 | 613 | |||
614 | /* Rewrite TCP/UDP checksum. */ | 614 | /* Rewrite TCP/UDP checksum. */ | |
615 | memcpy(ocksum, &cksum, sizeof(uint16_t)); | 615 | memcpy(ocksum, &cksum, sizeof(uint16_t)); | |
616 | return true; | 616 | return true; | |
617 | } | 617 | } | |
618 | 618 | |||
619 | /* | 619 | /* | |
620 | * npf_napt_rwr: perform address and/or port translation. | |||
621 | */ | |||
622 | int | |||
623 | npf_napt_rwr(const npf_cache_t *npc, u_int which, | |||
624 | const npf_addr_t *addr, const in_addr_t port) | |||
625 | { | |||
626 | const unsigned proto = npc->npc_proto; | |||
627 | ||||
628 | /* | |||
629 | * Rewrite IP and/or TCP/UDP checksums first, since we need the | |||
630 | * current (old) address/port for the calculations. Then perform | |||
631 | * the address translation i.e. rewrite source or destination. | |||
632 | */ | |||
633 | if (!npf_rwrcksum(npc, which, addr, port)) { | |||
634 | return EINVAL; | |||
635 | } | |||
636 | if (!npf_rwrip(npc, which, addr)) { | |||
637 | return EINVAL; | |||
638 | } | |||
639 | if (port == 0) { | |||
640 | /* Done. */ | |||
641 | return 0; | |||
642 | } | |||
643 | ||||
644 | switch (proto) { | |||
645 | case IPPROTO_TCP: | |||
646 | case IPPROTO_UDP: | |||
647 | /* Rewrite source/destination port. */ | |||
648 | if (!npf_rwrport(npc, which, port)) { | |||
649 | return EINVAL; | |||
650 | } | |||
651 | break; | |||
652 | case IPPROTO_ICMP: | |||
653 | case IPPROTO_ICMPV6: | |||
654 | KASSERT(npf_iscached(npc, NPC_ICMP)); | |||
655 | /* Nothing. */ | |||
656 | break; | |||
657 | default: | |||
658 | return ENOTSUP; | |||
659 | } | |||
660 | return 0; | |||
661 | } | |||
662 | ||||
663 | /* | |||
620 | * IPv6-to-IPv6 Network Prefix Translation (NPTv6), as per RFC 6296. | 664 | * IPv6-to-IPv6 Network Prefix Translation (NPTv6), as per RFC 6296. | |
621 | */ | 665 | */ | |
622 | 666 | |||
623 | int | 667 | int | |
624 | npf_npt66_rwr(const npf_cache_t *npc, u_int which, const npf_addr_t *pref, | 668 | npf_npt66_rwr(const npf_cache_t *npc, u_int which, const npf_addr_t *pref, | |
625 | npf_netmask_t len, uint16_t adj) | 669 | npf_netmask_t len, uint16_t adj) | |
626 | { | 670 | { | |
627 | npf_addr_t *addr = npc->npc_ips[which]; | 671 | npf_addr_t *addr = npc->npc_ips[which]; | |
628 | unsigned remnant, word, preflen = len >> 4; | 672 | unsigned remnant, word, preflen = len >> 4; | |
629 | uint32_t sum; | 673 | uint32_t sum; | |
630 | 674 | |||
631 | KASSERT(which == NPF_SRC || which == NPF_DST); | 675 | KASSERT(which == NPF_SRC || which == NPF_DST); | |
632 | 676 |
--- src/sys/net/npf/npf_nat.c 2014/02/13 03:34:40 1.25
+++ src/sys/net/npf/npf_nat.c 2014/02/19 03:51:31 1.26
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: npf_nat.c,v 1.25 2014/02/13 03:34:40 rmind Exp $ */ | 1 | /* $NetBSD: npf_nat.c,v 1.26 2014/02/19 03:51:31 rmind Exp $ */ | |
2 | 2 | |||
3 | /*- | 3 | /*- | |
4 | * Copyright (c) 2014 Mindaugas Rasiukevicius <rmind at netbsd org> | 4 | * Copyright (c) 2014 Mindaugas Rasiukevicius <rmind at netbsd org> | |
5 | * Copyright (c) 2010-2013 The NetBSD Foundation, Inc. | 5 | * Copyright (c) 2010-2013 The NetBSD Foundation, Inc. | |
6 | * All rights reserved. | 6 | * All rights reserved. | |
7 | * | 7 | * | |
8 | * This material is based upon work partially supported by The | 8 | * This material is based upon work partially supported by The | |
9 | * NetBSD Foundation under a contract with Mindaugas Rasiukevicius. | 9 | * NetBSD Foundation under a contract with Mindaugas Rasiukevicius. | |
10 | * | 10 | * | |
11 | * Redistribution and use in source and binary forms, with or without | 11 | * Redistribution and use in source and binary forms, with or without | |
12 | * modification, are permitted provided that the following conditions | 12 | * modification, are permitted provided that the following conditions | |
13 | * are met: | 13 | * are met: | |
14 | * 1. Redistributions of source code must retain the above copyright | 14 | * 1. Redistributions of source code must retain the above copyright | |
@@ -61,27 +61,27 @@ | @@ -61,27 +61,27 @@ | |||
61 | * | 61 | * | |
62 | * Sessions, translation entries and their life-cycle | 62 | * Sessions, translation entries and their life-cycle | |
63 | * | 63 | * | |
64 | * NAT module relies on session management module. Each translated | 64 | * NAT module relies on session management module. Each translated | |
65 | * session has an associated translation entry (npf_nat_t), which | 65 | * session has an associated translation entry (npf_nat_t), which | |
66 | * contains information used for backwards stream translation, i.e. | 66 | * contains information used for backwards stream translation, i.e. | |
67 | * original IP address with port and translation port, allocated from | 67 | * original IP address with port and translation port, allocated from | |
68 | * the port map. Each NAT entry is associated with the policy, which | 68 | * the port map. Each NAT entry is associated with the policy, which | |
69 | * contains translation IP address. Allocated port is returned to the | 69 | * contains translation IP address. Allocated port is returned to the | |
70 | * port map and NAT entry is destroyed when session expires. | 70 | * port map and NAT entry is destroyed when session expires. | |
71 | */ | 71 | */ | |
72 | 72 | |||
73 | #include <sys/cdefs.h> | 73 | #include <sys/cdefs.h> | |
74 | __KERNEL_RCSID(0, "$NetBSD: npf_nat.c,v 1.25 2014/02/13 03:34:40 rmind Exp $"); | 74 | __KERNEL_RCSID(0, "$NetBSD: npf_nat.c,v 1.26 2014/02/19 03:51:31 rmind Exp $"); | |
75 | 75 | |||
76 | #include <sys/param.h> | 76 | #include <sys/param.h> | |
77 | #include <sys/types.h> | 77 | #include <sys/types.h> | |
78 | 78 | |||
79 | #include <sys/atomic.h> | 79 | #include <sys/atomic.h> | |
80 | #include <sys/bitops.h> | 80 | #include <sys/bitops.h> | |
81 | #include <sys/condvar.h> | 81 | #include <sys/condvar.h> | |
82 | #include <sys/kmem.h> | 82 | #include <sys/kmem.h> | |
83 | #include <sys/mutex.h> | 83 | #include <sys/mutex.h> | |
84 | #include <sys/pool.h> | 84 | #include <sys/pool.h> | |
85 | #include <sys/proc.h> | 85 | #include <sys/proc.h> | |
86 | #include <sys/cprng.h> | 86 | #include <sys/cprng.h> | |
87 | 87 | |||
@@ -539,121 +539,78 @@ npf_nat_create(npf_cache_t *npc, npf_nat | @@ -539,121 +539,78 @@ npf_nat_create(npf_cache_t *npc, npf_nat | |||
539 | if ((np->n_flags & NPF_NAT_PORTMAP) != 0) { | 539 | if ((np->n_flags & NPF_NAT_PORTMAP) != 0) { | |
540 | nt->nt_tport = npf_nat_getport(np); | 540 | nt->nt_tport = npf_nat_getport(np); | |
541 | } else { | 541 | } else { | |
542 | nt->nt_tport = np->n_tport; | 542 | nt->nt_tport = np->n_tport; | |
543 | } | 543 | } | |
544 | out: | 544 | out: | |
545 | mutex_enter(&np->n_lock); | 545 | mutex_enter(&np->n_lock); | |
546 | LIST_INSERT_HEAD(&np->n_nat_list, nt, nt_entry); | 546 | LIST_INSERT_HEAD(&np->n_nat_list, nt, nt_entry); | |
547 | mutex_exit(&np->n_lock); | 547 | mutex_exit(&np->n_lock); | |
548 | return nt; | 548 | return nt; | |
549 | } | 549 | } | |
550 | 550 | |||
551 | /* | 551 | /* | |
552 | * npf_nat_rwr: perform address and/or port translation. | |||
553 | */ | |||
554 | static int | |||
555 | npf_nat_rwr(npf_cache_t *npc, const npf_natpolicy_t *np, | |||
556 | const npf_addr_t *addr, const in_addr_t port, bool forw) | |||
557 | { | |||
558 | const unsigned proto = npc->npc_proto; | |||
559 | const u_int which = npf_nat_which(np->n_type, forw); | |||
560 | ||||
561 | /* | |||
562 | * Rewrite IP and/or TCP/UDP checksums first, since we need the | |||
563 | * current (old) address/port for the calculations. Then perform | |||
564 | * the address translation i.e. rewrite source or destination. | |||
565 | */ | |||
566 | if (!npf_rwrcksum(npc, which, addr, port)) { | |||
567 | return EINVAL; | |||
568 | } | |||
569 | if (!npf_rwrip(npc, which, addr)) { | |||
570 | return EINVAL; | |||
571 | } | |||
572 | if ((np->n_flags & NPF_NAT_PORTS) == 0) { | |||
573 | /* Done. */ | |||
574 | return 0; | |||
575 | } | |||
576 | ||||
577 | switch (proto) { | |||
578 | case IPPROTO_TCP: | |||
579 | case IPPROTO_UDP: | |||
580 | /* Rewrite source/destination port. */ | |||
581 | if (!npf_rwrport(npc, which, port)) { | |||
582 | return EINVAL; | |||
583 | } | |||
584 | break; | |||
585 | case IPPROTO_ICMP: | |||
586 | KASSERT(npf_iscached(npc, NPC_ICMP)); | |||
587 | /* Nothing. */ | |||
588 | break; | |||
589 | default: | |||
590 | return ENOTSUP; | |||
591 | } | |||
592 | return 0; | |||
593 | } | |||
594 | ||||
595 | /* | |||
596 | * npf_nat_translate: perform translation given the state data. | 552 | * npf_nat_translate: perform translation given the state data. | |
597 | */ | 553 | */ | |
598 | int | 554 | static inline int | |
599 | npf_nat_translate(npf_cache_t *npc, nbuf_t *nbuf, npf_nat_t *nt, bool forw) | 555 | npf_nat_translate(npf_cache_t *npc, nbuf_t *nbuf, npf_nat_t *nt, bool forw) | |
600 | { | 556 | { | |
601 | const npf_natpolicy_t *np = nt->nt_natpolicy; | 557 | const npf_natpolicy_t *np = nt->nt_natpolicy; | |
558 | const u_int which = npf_nat_which(np->n_type, forw); | |||
602 | const npf_addr_t *addr; | 559 | const npf_addr_t *addr; | |
603 | in_port_t port; | 560 | in_port_t port; | |
604 | 561 | |||
605 | KASSERT(npf_iscached(npc, NPC_IP46)); | 562 | KASSERT(npf_iscached(npc, NPC_IP46)); | |
606 | KASSERT(npf_iscached(npc, NPC_LAYER4)); | 563 | KASSERT(npf_iscached(npc, NPC_LAYER4)); | |
607 | KASSERT(!nbuf_flag_p(nbuf, NBUF_DATAREF_RESET)); | |||
608 | 564 | |||
609 | if (forw) { | 565 | if (forw) { | |
610 | /* "Forwards" stream: use translation address/port. */ | 566 | /* "Forwards" stream: use translation address/port. */ | |
611 | addr = &np->n_taddr; | 567 | addr = &np->n_taddr; | |
612 | port = nt->nt_tport; | 568 | port = nt->nt_tport; | |
613 | } else { | 569 | } else { | |
614 | /* "Backwards" stream: use original address/port. */ | 570 | /* "Backwards" stream: use original address/port. */ | |
615 | addr = &nt->nt_oaddr; | 571 | addr = &nt->nt_oaddr; | |
616 | port = nt->nt_oport; | 572 | port = nt->nt_oport; | |
617 | } | 573 | } | |
618 | KASSERT((np->n_flags & NPF_NAT_PORTS) != 0 || port == 0); | 574 | KASSERT((np->n_flags & NPF_NAT_PORTS) != 0 || port == 0); | |
619 | 575 | |||
620 | /* Execute ALG hook first. */ | 576 | /* Execute ALG translation first. */ | |
621 | if ((npc->npc_info & NPC_ALG_EXEC) == 0) { | 577 | if ((npc->npc_info & NPC_ALG_EXEC) == 0) { | |
622 | npc->npc_info |= NPC_ALG_EXEC; | 578 | npc->npc_info |= NPC_ALG_EXEC; | |
623 | npf_alg_exec(npc, nbuf, nt, forw); | 579 | npf_alg_exec(npc, nbuf, nt, forw); | |
580 | npf_recache(npc, nbuf); | |||
624 | } | 581 | } | |
582 | KASSERT(!nbuf_flag_p(nbuf, NBUF_DATAREF_RESET)); | |||
625 | 583 | |||
626 | /* Finally, perform the translation. */ | 584 | /* Finally, perform the translation. */ | |
627 | return npf_nat_rwr(npc, np, addr, port, forw); | 585 | return npf_napt_rwr(npc, which, addr, port); | |
628 | } | 586 | } | |
629 | 587 | |||
630 | /* | 588 | /* | |
631 | * npf_nat_algo: perform the translation given the algorithm. | 589 | * npf_nat_algo: perform the translation given the algorithm. | |
632 | */ | 590 | */ | |
633 | static inline int | 591 | static inline int | |
634 | npf_nat_algo(npf_cache_t *npc, const npf_natpolicy_t *np, bool forw) | 592 | npf_nat_algo(npf_cache_t *npc, const npf_natpolicy_t *np, bool forw) | |
635 | { | 593 | { | |
636 | u_int which; | 594 | const u_int which = npf_nat_which(np->n_type, forw); | |
637 | int error; | 595 | int error; | |
638 | 596 | |||
639 | switch (np->n_algo) { | 597 | switch (np->n_algo) { | |
640 | case NPF_ALGO_NPT66: | 598 | case NPF_ALGO_NPT66: | |
641 | which = npf_nat_which(np->n_type, forw); | |||
642 | error = npf_npt66_rwr(npc, which, &np->n_taddr, | 599 | error = npf_npt66_rwr(npc, which, &np->n_taddr, | |
643 | np->n_tmask, np->n_npt66_adj); | 600 | np->n_tmask, np->n_npt66_adj); | |
644 | break; | 601 | break; | |
645 | default: | 602 | default: | |
646 | error = npf_nat_rwr(npc, np, &np->n_taddr, np->n_tport, forw); | 603 | error = npf_napt_rwr(npc, which, &np->n_taddr, np->n_tport); | |
647 | break; | 604 | break; | |
648 | } | 605 | } | |
649 | 606 | |||
650 | return error; | 607 | return error; | |
651 | } | 608 | } | |
652 | 609 | |||
653 | /* | 610 | /* | |
654 | * npf_do_nat: | 611 | * npf_do_nat: | |
655 | * - Inspect packet for a NAT policy, unless a session with a NAT | 612 | * - Inspect packet for a NAT policy, unless a session with a NAT | |
656 | * association already exists. In such case, determine whether it | 613 | * association already exists. In such case, determine whether it | |
657 | * is a "forwards" or "backwards" stream. | 614 | * is a "forwards" or "backwards" stream. | |
658 | * - Perform translation: rewrite source or destination fields, | 615 | * - Perform translation: rewrite source or destination fields, | |
659 | * depending on translation type and direction. | 616 | * depending on translation type and direction. |