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>
