On FreeBSD 4.7, I cross checked the code on FreeBSD HEAD, they are the same.

The following rule did not catch the ESP packet and do the redirect.

"rdr xl0 from 172.31.2.146 to 172.31.2.149 -> 10.1.19.1 port 0 esp"

The rdr rule is the only NAT rule on the machine. I just want to isolate the problem.

I did the following kernel tracing into the ipfilter and execution path is:

An input ESP packet reaches the in_input() -> fr_check() -> ip_natin()
it reaches the follow code chunk in ip_natin(), I added an extra printf line:
===========================================
maskloop:
iph = in.s_addr & htonl(msk);
hv = NAT_HASH_FN(iph, 0, ipf_rdrrules_sz);
for (np = rdr_rules[hv]; np; np = np->in_rnext) {
printf("np proto=%d %d flags=%x %x name= %x %x\n",
np->in_p,fin->fin_p,
np->in_flags,nflags,
np->in_ifp,
ifp);
* if ((np->in_ifp && (np->in_ifp != ifp)) ||
(np->in_p && (np->in_p != fin->fin_p)) ||
(np->in_flags && !(nflags & np->in_flags)))
continue;
if (np->in_flags & IPN_FILTER) {
if (!nat_match(fin, np, ip))
continue;
} else if ((in.s_addr & np->in_outmsk) != np->in_outip)
continue;
if ((!np->in_pmin || (np->in_flags & IPN_FILTER) ||
((ntohs(np->in_pmax) >= ntohs(dport)) &&
(ntohs(dport) >= ntohs(np->in_pmin)))))
if ((nat = nat_new(fin, ip, np, NULL, nflags,
NAT_INBOUND))) {
np->in_hits++;
break;
}
}
=======================================================
The rule did not match on the first if (marked by *). It was failed by the comparison of flags, where
the np->in_flags = 0x40 (IPN_FILTER) and nflags = 0.


This code is impossible for an non-TCP/UDP redirect rule with filtering src/dst to match because the nflags will always be zero, and the np_in_flags will at least have IPN_FILTER bit set to 1.

Darren:

Can we take out the line (np->in_flags && !(nflags & np->in_flags)))? It only test, in the case of TCP/UDP, whether the incoming packet is TCP or UDP. This condition is already tested by line above it which compares protocol ID.

Regards,
Ming

Reply via email to