NPF: fix the recent breakage of the traceroute ALG. Also, simplify and

refactor a little bit.
This commit is contained in:
rmind 2014-02-19 03:51:31 +00:00
parent 27b83b3d9e
commit 022864892f
4 changed files with 82 additions and 73 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: npf_alg_icmp.c,v 1.19 2014/02/16 22:10:40 rmind Exp $ */
/* $NetBSD: npf_alg_icmp.c,v 1.20 2014/02/19 03:51:31 rmind Exp $ */
/*-
* Copyright (c) 2010 The NetBSD Foundation, Inc.
@ -34,7 +34,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: npf_alg_icmp.c,v 1.19 2014/02/16 22:10:40 rmind Exp $");
__KERNEL_RCSID(0, "$NetBSD: npf_alg_icmp.c,v 1.20 2014/02/19 03:51:31 rmind Exp $");
#include <sys/param.h>
#include <sys/module.h>
@ -305,6 +305,7 @@ npfa_icmp_session(npf_cache_t *npc, nbuf_t *nbuf, int di)
static bool
npfa_icmp_nat(npf_cache_t *npc, nbuf_t *nbuf, npf_nat_t *nt, bool forw)
{
const u_int which = NPF_SRC;
npf_cache_t enpc;
if (forw || !npf_iscached(npc, NPC_ICMP))
@ -315,6 +316,9 @@ npfa_icmp_nat(npf_cache_t *npc, nbuf_t *nbuf, npf_nat_t *nt, bool forw)
KASSERT(npf_iscached(&enpc, NPC_IP46));
KASSERT(npf_iscached(&enpc, NPC_LAYER4));
/*
* ICMP: fetch the current checksum we are going to fixup.
*/
struct icmp *ic = npc->npc_l4.icmp;
uint16_t cksum = ic->icmp_cksum;
@ -322,12 +326,9 @@ npfa_icmp_nat(npf_cache_t *npc, nbuf_t *nbuf, npf_nat_t *nt, bool forw)
offsetof(struct icmp6_hdr, icmp6_cksum));
/*
* Retrieve the original address and port, then calculate ICMP
* checksum for these changes in the embedded packet. While data
* is not rewritten in the cache, save IP and TCP/UDP checksums.
*
* XXX: Assumes NPF_NATOUT (source address/port). Currently,
* npfa_icmp_match() matches only for the PFIL_OUT traffic.
* Fetch the IP and port in the _embedded_ packet. Also, fetch
* the IPv4 and TCP/UDP checksums before they are rewritten.
* Calculate the part of the ICMP checksum fixup.
*/
const int proto = enpc.npc_proto;
uint16_t ipcksum = 0, l4cksum = 0;
@ -340,7 +341,7 @@ npfa_icmp_nat(npf_cache_t *npc, nbuf_t *nbuf, npf_nat_t *nt, bool forw)
const struct ip *eip = enpc.npc_ip.v4;
ipcksum = eip->ip_sum;
}
cksum = npf_addr_cksum(cksum, enpc.npc_alen, enpc.npc_ips[NPF_SRC], addr);
cksum = npf_addr_cksum(cksum, enpc.npc_alen, enpc.npc_ips[which], addr);
switch (proto) {
case IPPROTO_TCP: {
@ -363,17 +364,23 @@ npfa_icmp_nat(npf_cache_t *npc, nbuf_t *nbuf, npf_nat_t *nt, bool forw)
}
/*
* Rewrite the source IP address and port of the embedded IP header,
* which represents the original packet. This updates the checksums
* in the embedded packet.
* Translate the embedded packet. The following changes will
* be performed by npf_napt_rwr():
*
* 1) Rewrite the IP address and, if not ICMP, port.
* 2) Rewrite the TCP/UDP checksum (if not ICMP).
* 3) Rewrite the IPv4 checksum for (1) and (2).
*
* XXX: Assumes NPF_NATOUT (source address/port). Currently,
* npfa_icmp_match() matches only for the PFIL_OUT traffic.
*/
if (npf_nat_translate(&enpc, nbuf, nt, forw)) {
if (npf_napt_rwr(&enpc, which, addr, port)) {
return false;
}
/*
* Finish calculation of the ICMP checksum: include the checksum
* change in the embedded packet.
* Finally, finish the ICMP checksum fixup: include the checksum
* changes in the embedded packet.
*/
if (npf_iscached(&enpc, NPC_IP4)) {
const struct ip *eip = enpc.npc_ip.v4;

View File

@ -1,4 +1,4 @@
/* $NetBSD: npf_impl.h,v 1.48 2014/02/16 22:10:40 rmind Exp $ */
/* $NetBSD: npf_impl.h,v 1.49 2014/02/19 03:51:31 rmind Exp $ */
/*-
* Copyright (c) 2009-2014 The NetBSD Foundation, Inc.
@ -200,6 +200,8 @@ bool npf_rwrip(const npf_cache_t *, u_int, const npf_addr_t *);
bool npf_rwrport(const npf_cache_t *, u_int, const in_port_t);
bool npf_rwrcksum(const npf_cache_t *, u_int,
const npf_addr_t *, const in_port_t);
int npf_napt_rwr(const npf_cache_t *, u_int, const npf_addr_t *,
const in_addr_t);
int npf_npt66_rwr(const npf_cache_t *, u_int, const npf_addr_t *,
npf_netmask_t, uint16_t);
@ -341,7 +343,6 @@ bool npf_nat_sharepm(npf_natpolicy_t *, npf_natpolicy_t *);
void npf_nat_freealg(npf_natpolicy_t *, npf_alg_t *);
int npf_do_nat(npf_cache_t *, npf_session_t *, nbuf_t *, const int);
int npf_nat_translate(npf_cache_t *, nbuf_t *, npf_nat_t *, bool);
void npf_nat_destroy(npf_nat_t *);
void npf_nat_getorig(npf_nat_t *, npf_addr_t **, in_port_t *);
void npf_nat_gettrans(npf_nat_t *, npf_addr_t **, in_port_t *);

View File

@ -1,4 +1,4 @@
/* $NetBSD: npf_inet.c,v 1.29 2014/02/13 03:34:40 rmind Exp $ */
/* $NetBSD: npf_inet.c,v 1.30 2014/02/19 03:51:31 rmind Exp $ */
/*-
* Copyright (c) 2009-2014 The NetBSD Foundation, Inc.
@ -39,7 +39,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: npf_inet.c,v 1.29 2014/02/13 03:34:40 rmind Exp $");
__KERNEL_RCSID(0, "$NetBSD: npf_inet.c,v 1.30 2014/02/19 03:51:31 rmind Exp $");
#include <sys/param.h>
#include <sys/types.h>
@ -578,7 +578,7 @@ npf_rwrcksum(const npf_cache_t *npc, u_int which,
}
/* Nothing else to do for ICMP. */
if (proto == IPPROTO_ICMP) {
if (proto == IPPROTO_ICMP || proto == IPPROTO_ICMPV6) {
return true;
}
KASSERT(npf_iscached(npc, NPC_TCP) || npf_iscached(npc, NPC_UDP));
@ -616,6 +616,50 @@ npf_rwrcksum(const npf_cache_t *npc, u_int which,
return true;
}
/*
* npf_napt_rwr: perform address and/or port translation.
*/
int
npf_napt_rwr(const npf_cache_t *npc, u_int which,
const npf_addr_t *addr, const in_addr_t port)
{
const unsigned proto = npc->npc_proto;
/*
* Rewrite IP and/or TCP/UDP checksums first, since we need the
* current (old) address/port for the calculations. Then perform
* the address translation i.e. rewrite source or destination.
*/
if (!npf_rwrcksum(npc, which, addr, port)) {
return EINVAL;
}
if (!npf_rwrip(npc, which, addr)) {
return EINVAL;
}
if (port == 0) {
/* Done. */
return 0;
}
switch (proto) {
case IPPROTO_TCP:
case IPPROTO_UDP:
/* Rewrite source/destination port. */
if (!npf_rwrport(npc, which, port)) {
return EINVAL;
}
break;
case IPPROTO_ICMP:
case IPPROTO_ICMPV6:
KASSERT(npf_iscached(npc, NPC_ICMP));
/* Nothing. */
break;
default:
return ENOTSUP;
}
return 0;
}
/*
* IPv6-to-IPv6 Network Prefix Translation (NPTv6), as per RFC 6296.
*/

View File

@ -1,4 +1,4 @@
/* $NetBSD: npf_nat.c,v 1.25 2014/02/13 03:34:40 rmind Exp $ */
/* $NetBSD: npf_nat.c,v 1.26 2014/02/19 03:51:31 rmind Exp $ */
/*-
* Copyright (c) 2014 Mindaugas Rasiukevicius <rmind at netbsd org>
@ -71,7 +71,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: npf_nat.c,v 1.25 2014/02/13 03:34:40 rmind Exp $");
__KERNEL_RCSID(0, "$NetBSD: npf_nat.c,v 1.26 2014/02/19 03:51:31 rmind Exp $");
#include <sys/param.h>
#include <sys/types.h>
@ -548,63 +548,19 @@ out:
return nt;
}
/*
* npf_nat_rwr: perform address and/or port translation.
*/
static int
npf_nat_rwr(npf_cache_t *npc, const npf_natpolicy_t *np,
const npf_addr_t *addr, const in_addr_t port, bool forw)
{
const unsigned proto = npc->npc_proto;
const u_int which = npf_nat_which(np->n_type, forw);
/*
* Rewrite IP and/or TCP/UDP checksums first, since we need the
* current (old) address/port for the calculations. Then perform
* the address translation i.e. rewrite source or destination.
*/
if (!npf_rwrcksum(npc, which, addr, port)) {
return EINVAL;
}
if (!npf_rwrip(npc, which, addr)) {
return EINVAL;
}
if ((np->n_flags & NPF_NAT_PORTS) == 0) {
/* Done. */
return 0;
}
switch (proto) {
case IPPROTO_TCP:
case IPPROTO_UDP:
/* Rewrite source/destination port. */
if (!npf_rwrport(npc, which, port)) {
return EINVAL;
}
break;
case IPPROTO_ICMP:
KASSERT(npf_iscached(npc, NPC_ICMP));
/* Nothing. */
break;
default:
return ENOTSUP;
}
return 0;
}
/*
* npf_nat_translate: perform translation given the state data.
*/
int
static inline int
npf_nat_translate(npf_cache_t *npc, nbuf_t *nbuf, npf_nat_t *nt, bool forw)
{
const npf_natpolicy_t *np = nt->nt_natpolicy;
const u_int which = npf_nat_which(np->n_type, forw);
const npf_addr_t *addr;
in_port_t port;
KASSERT(npf_iscached(npc, NPC_IP46));
KASSERT(npf_iscached(npc, NPC_LAYER4));
KASSERT(!nbuf_flag_p(nbuf, NBUF_DATAREF_RESET));
if (forw) {
/* "Forwards" stream: use translation address/port. */
@ -617,14 +573,16 @@ npf_nat_translate(npf_cache_t *npc, nbuf_t *nbuf, npf_nat_t *nt, bool forw)
}
KASSERT((np->n_flags & NPF_NAT_PORTS) != 0 || port == 0);
/* Execute ALG hook first. */
/* Execute ALG translation first. */
if ((npc->npc_info & NPC_ALG_EXEC) == 0) {
npc->npc_info |= NPC_ALG_EXEC;
npf_alg_exec(npc, nbuf, nt, forw);
npf_recache(npc, nbuf);
}
KASSERT(!nbuf_flag_p(nbuf, NBUF_DATAREF_RESET));
/* Finally, perform the translation. */
return npf_nat_rwr(npc, np, addr, port, forw);
return npf_napt_rwr(npc, which, addr, port);
}
/*
@ -633,17 +591,16 @@ npf_nat_translate(npf_cache_t *npc, nbuf_t *nbuf, npf_nat_t *nt, bool forw)
static inline int
npf_nat_algo(npf_cache_t *npc, const npf_natpolicy_t *np, bool forw)
{
u_int which;
const u_int which = npf_nat_which(np->n_type, forw);
int error;
switch (np->n_algo) {
case NPF_ALGO_NPT66:
which = npf_nat_which(np->n_type, forw);
error = npf_npt66_rwr(npc, which, &np->n_taddr,
np->n_tmask, np->n_npt66_adj);
break;
default:
error = npf_nat_rwr(npc, np, &np->n_taddr, np->n_tport, forw);
error = npf_napt_rwr(npc, which, &np->n_taddr, np->n_tport);
break;
}