Bug 27782

Summary: ipf packet munging bug using "to" option in rule
Product: Base System Reporter: Louis Mamakos <louie>
Component: kernAssignee: Darern Reed <darrenr>
Status: Closed FIXED    
Severity: Affects Only Me CC: net
Priority: Normal    
Version: 4.3-STABLE   
Hardware: Any   
OS: Any   
Attachments:
Description Flags
file.diff none

Description Louis Mamakos 2001-05-31 01:00:02 UTC
I'm using ipf on a machine to perform some stupid packet tricks, including
the dubious operation of fowarding traffic out an alternative network
interface based on the source address of the packet.  The reasons why
are beyond the scope of this PR.

I have a rule that looks something like this:

pass out quick on de0 from any to any head 11
block out quick on de0 to tun0 from 144.202.0.0/16 to !144.202.0.0/16 group 11
...

The intent is that when packets from 144.202.0.0/16 arrive on this
host, that they get forcebly shoved out the tun0 network interface,
rather than taking the expect forwarding path via the de0 interface.

This works MOST OF THE TIME.  However, sending packets larger than a
certain size results in the packet being mangled.  It turns out this
happens when the packet is large enough that it can no longer be
contained within a single mbuf, and there's an mbuf cluster attached.
There is code in sys/netinet/ip_fil.c:ipfr_fastroute() which does
something like this (paraphrased):n

                ip->ip_len = htons(ip->ip_len);
                ip->ip_off = htons(ip->ip_off);
                if (!ip->ip_sum)
                        ip->ip_sum = in_cksum(m, hlen);

                error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst,
                                          ro->ro_rt);
                if (i) {
                        ip->ip_id = ntohs(ip->ip_id);
                        ip->ip_len = ntohs(ip->ip_len);
                        ip->ip_off = ntohs(ip->ip_off);
                }

The problem is that if the outbound network interface saves a pointer
to the cluster, it will pick up up the version of the packet after
it's been modified by the ntohs() calls after the if_output routine
is called.  In my case, this happens on a tunnel interface but
other network interfaces which can DMA directly from the mbufs rather
than copying the data will suffer from the same problem.

Fix: I did a brutal hack in ipfr_fastroute() to make a copy of the
mbuf if it's not M_WRITABLE(), and then arranged for the 
if (i) case in the code above to never get run to corrupt the
data in the mbuf.

I don't understand the global structure of the ipf code well
enough to know if that's a "proper" way to solve the problem
or not.  After applying the workaround, traffic is now working 
where previously I was getting nasty checksum errors and the
like due to some of the fields being byte-swapped.  I would
imagine that big-endian systems and those with network interfaces
that require the transmit data to be copied wouldn't have
seen this problem previously.
How-To-Repeat: 	as described, sorta..
Comment 1 Doug Barton freebsd_committer freebsd_triage 2001-05-31 08:11:34 UTC
Responsible Changed
From-To: freebsd-bugs->darrenr


Darren is Mr. Ipfilter
Comment 2 jasper 2001-07-17 20:57:12 UTC
FWIW i've had this problem too, and the patch on this PR fixed it.

-- 
Internet Vision          Internet Consultancy           Tel: 020 7589 4500
60 Albert Court            & Web development            Fax: 020 7589 4522
Prince Consort Road                                   vision@ivision.co.uk
London SW7 2BE                                   http://www.ivision.co.uk/
Comment 3 Darern Reed freebsd_committer freebsd_triage 2001-10-20 05:51:27 UTC
State Changed
From-To: open->closed

this has been imported into -current and -stable