Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 15 Feb 2002 18:15:52 -0700
From:      "Aaron D. Gifford" <agifford@infowest.com>
To:        freebsd-net@freebsd.org
Cc:        kudzu@tenebras.com
Subject:   Re: Bug in stateful code?
Message-ID:  <20020216011553.79227214BC@ns1.infowest.com>
In-Reply-To: <3C6DA100.3080108@tenebras.com>
References:  <20020215225647.DBAB521CE8@ns1.infowest.com> <3C6DA100.3080108@tenebras.com>

next in thread | previous in thread | raw e-mail | index | archive | help
On Friday 15 February 2002 05:00 pm, Michael Sierchio <kudzu@tenebras.com> 
wrote:
> Aaron D. Gifford wrote:
> > When it hits check-state, while it DOES match the "X.Y.Z.23 1549<->
> > X.Y.Z.44 22" dynamic rule in principal, it FAILS to match because the
> > dynamic rule is expecting to see a SYN-ACK response from the remote host
> > FIRST (remember, the SYN-ACK never matched this particular dynamic rule).
> >  Thus this dynamic rule STILL sits, expecting SYN-ACK.
> >
> > Since no further rules match, if you default to deny, your ACK packet
> > gets dropped/denied.
> >
> > Is this the behavior you are seeing?
>
> The packet is never dropped, it's just that -- as Crist previously
> pointed out -- it matches an earlier rule, so it never changes
> the state of the dynamic rule in question.  It's sometimes useful to
> use 'add count' rules before and after 'divert natd' to see what's
> happening.
>


Okay, I understand now.  You're saying that the last packet of the three-way 
TCP handshake (the SYN+ACK from the INSIDE to the OUTSIDE) is NOT dropped, 
but passed by the "X.Y.Z.23 1549<-> X.Y.Z.44 22" rule WITHOUT that rule being 
updated.  That indeed is a bug.

Reading the code in /usr/src/sys/netinet/ip_fw.c (on my 4.5-STABLE box), I 
see where the problem is.  Around line 780, there is a switch()/case: 
statement that handles normal TCP states.

Because of your ruleset, you have created a dynamic rule that only sees the 
INSIDE-to-OUTSIDE packets but will NEVER see the reverse packets (the other 
dynamic rule your original post mentions will behave normally, seeing the 
packets in BOTH directions).

The current ip_fw.c code there, in this case will PASS the matched packet, 
and update the timeout using dyn_rst_lifetime because it falls through the 
switch() statement to the default: section.

I don't know what the correct "fix" is.  My gut instinct is that ifpw's 
default: seciton (line 798) should just reject/drop the packet (return NULL) 
instead of what it does today, passing the packet with a very short timeout.  
If there are valid states that are not yet handled, they should be added and 
handled.

Perhaps a useful solution to the bug that might have helped warn you in your 
specific situation would be to detect such half-seen behavior in the default 
case, and log a warning, since this is likely to be a common problem with 
anyone using ipfw stateful rules and natd.

Something like:

default:
  if (q->state == TH_SYN | TH_ACK)
    /*
     * Both forward SYN and SYN+ACK packets have been seen,
     * without a reverse SYN+ACK packet in between, due to a
     * buggy rule set, or bogus traffic from the originating host.
     */
    if (fw_verbose) {
      log(LOG_SECURITY | LOG_NOTICE,
        "ipfw: Invalid stateful TCP rule (from %d): Middle packet "
        "missing from three-way TCP handshake.",
        q->parent->fw_number);
      return NULL;	/* Drop the packet as if not matched */
    }

If you'd seen such a warning right away, without it passing your packets, you 
would have known it was a ruleset problem, or else asked someone on the list 
about the error message in the logs.

Thoughts?

Aaron out.



To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-net" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20020216011553.79227214BC>