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>