Re: ipfilter causing kernel panic in FreeBSD 6.1

Steve Clark <[email protected]>
Newsgroups gmane.comp.security.firewalls.ipfilter
Message-ID <[email protected]>
Mire, John wrote:
> Would it make sense to rearrange the order of ipfw vs ipfilter so it's
> first in and last out so you could use ipfw just for that kind of
> utility to "screen" frags, so it's
> ipfw(in)->ipnat(in)->ipfilter(in)->ipfilter(out)->ipfw(out)
> 
Hi John,
I am pretty sure it already works that way on FreeBSD.
The original problem was caused by receiving a the initial fragment
in a series getting lost on the net. When the second fragment came along
ip_nat said oh this packet matches an existing nat rule and it is not the
initial packet so I must already have an entry in the nat table so I don't need
to do a look up - and ip_nat then ended up dereferencing a null pointer causing
a kernel panic.

The patch below works if you receive fragmented packets that match a nat rule they
are passed thru just fine, but if you don't have a matching rule the initial frag packet is
passed and subsequent ones are dropped - they show up in the firewall log similar to this:
09:43:13.797016 gre2 @-1:-1 b 172.16.11.56 -> 10.254.23.51 PR udp len 20 (342) (frag 13734:322@1480) IN bad-NAT

>>-----Original Message-----
>>From: [email protected] [mailto:owner-
>>[email protected]] On Behalf Of Steve Clark
>>Sent: Thursday, May 22, 2008 6:10 AM
>>To: [email protected]
>>Cc: [email protected]; plyn >> Phillip Lynn
>>Subject: Re: ipfilter causing kernel panic in FreeBSD 6.1
>>
>>Darren Reed wrote:
>>
>>>Steve Clark wrote:
>>>
>>>
>>>>Darren Reed wrote:
>>>>
>>>>
>>>>>Steve Clark wrote:
>>>>>
>>>>>
>>>>>
>>>>>>...
>>>>>>Hi Darren,
>>>>>>
>>>>>>Since I knew it was night time "down under" I went ahead and just
>>>>>>changed to code
>>>>>>to print a message and return -1 in nat_finalise() then the tcp
>>>>>>pointer was null.
>>>>>>The system has stayed up now almost 24 hours - where yesterday it
>>>>>>had 20 panics.
>>>>>>
>>>>>>Is there some reason we wouldn't want to just dump/ignore this
>>>>>>packet, since it seems to
>>>>>>me that the initial syn and at least the first packet of the
>>>>>>fragmented series had gotten lost
>>>>>>and eventually will be retried.
>>>>>
>>>>>
>>>>>Well, the original packet that caused this problem was not
>>>>>part of a SYN - it was a midstream TCP packet.  I suspect
>>>>>something else is going on there.  It may be part of a
> 
> retransmitted
> 
>>>>>packet sent after the original NAT session is torn down.
>>>>>I don't know.  But obviously your policy allows the packet
>>>>>to be sent (and received) so the NAT code should make
>>>>>this possible.
>>>>>
>>>>>It might be more appropriate to not allow fragments that are
>>>>>not the first fragment (offset = 0) to form NAT sessions for
>>>>>the TCP/UDP protocols.  That I could understand.
>>>>>
>>>>
>>>>Yes that is what I was getting at. It is my understanding that in
>>>>freebsd ip_nat happens
>>>>before ip_filter - so we really can't filter these before they hit
>>>>ip_nat. Since they are externally
>>>>generated we would have to put another fw in front of this firewall
>>
>>to
>>
>>>>keep them out.
>>>
>>>
>>>Ok, then the patch below might be of use to you then.
>>>
>>>Darren
>>>
>>>
>>>
>>>diff -c -r2.195.2.105 ip_nat.c
>>>*** ip_nat.c    21 Dec 2007 23:03:24 -0000      2.195.2.105
>>>--- ip_nat.c    8 Feb 2008 02:27:04 -0000
>>>***************
>>>*** 3804,3809 ****
>>>--- 3804,3813 ----
>>>                 * If there is no current entry in the nat table for
>>>this IP#,
>>>                 * create one for it (if there is a matching rule).
>>>                 */
>>>+               if ((fin->fin_off != 0) && (fin->fin_flx &
>>
>>FI_TCPUDP)) {
>>
>>>+                       natfailed = -1;
>>>+                       goto nonatfrag;
>>>+               }
>>>                RWLOCK_EXIT(&ipf_nat);
>>>                msk = 0xffffffff;
>>>                nmsk = nat_masks;
>>>***************
>>>*** 3861,3866 ****
>>>--- 3865,3871 ----
>>>                MUTEX_DOWNGRADE(&ipf_nat);
>>>        }
>>>
>>>+ nonatfrag:
>>>        if (nat != NULL) {
>>>                rval = fr_natout(fin, nat, natadd, nflags);
>>>                if (rval == 1) {
>>>***************
>>>*** 4095,4100 ****
>>>--- 4100,4109 ----
>>>        } else {
>>>                u_32_t hv, msk, rmsk;
>>>
>>>+               if ((fin->fin_off != 0) && (fin->fin_flx &
>>
>>FI_TCPUDP)) {
>>
>>>+                       natfailed = -1;
>>>+                       goto nonatfrag;
>>>+               }
>>>                RWLOCK_EXIT(&ipf_nat);
>>>                rmsk = rdr_masks;
>>>                msk = 0xffffffff;
>>>***************
>>>*** 4155,4160 ****
>>>--- 4164,4171 ----
>>>                }
>>>                MUTEX_DOWNGRADE(&ipf_nat);
>>>        }
>>>+
>>>+ nonatfrag:
>>>        if (nat != NULL) {
>>>                rval = fr_natin(fin, nat, natadd, nflags);
>>>                if (rval == 1) {
>>>
>>>
>>
>>Hi Darren,
>>
>>Is it possible to make the above patch more selective in the frags it
>>drops? Meaning it drops
>>frags even if there is no matching ipnat rule. This allows the initial
>>fragment to pass then all succeeding
>>fragments get dropped.
>>
>>The ideal situation would be to drop any fragment after the first if
>>there was not already an entry in the
>>nat table and it matched a nat rule.
>>
>>Regards,
>>Steve
> 
> 
>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.