[4118] in linux-net channel archive

home help back first fref pref prev next nref lref last post

Problem in firewall code with RST packets

daemon@ATHENA.MIT.EDU (Dave Platt)
Tue Aug 20 19:06:00 1996

Date: 	Tue, 20 Aug 1996 14:32:01 -0700
From: Dave Platt <dplatt@iq.tvsoft.com>
To: linux-net@vger.rutgers.edu
Cc: Linus.Torvalds@helsinki.fi

I believe I've stumbled across a deficiency in the 2.0.x IP firewall
code, which can result in "stuck" or "half-closed" connections.

The problem has to do with the way in which the IP firewall code
distinguishes "packets which are an attempt to start up a new
connection" (SYN is set, and ACK is not set) from "packets which are
taking place over a connection that has already been started" (ACK is
set, SYN is irrelevant).  It's common for firewall rules to be very
strict about letting "start of connection" packets through, but to be
much more liberal about letting "established connection" packets
through.  All of this is very much consistent with the strategies
recommended by Chapman and Zwicky in "Building Internet Firewalls".

There's a problem, though - RST packets.  If the system "inside" the
firewall (the one being protected) has a connection open to the
outside world, and the far-end system crashes and reboots, and the
"inside" system tries to send additional data on this connection...
then things get stuck.  The additional outbound data gets through the
firewall OK (it has ACK set).  The outside system receives the data and
says "Whoa, this is for a connection which is no longer valid", and
sends a RST packet to reset the connection.  The RST does NOT have ACK
set in its header - at least, not always (and perhaps never, since the
far-end system has no knowledge of how to put a valid sequence number
in it).

The RST-without-ACK packet gets back to the firewall, and #SPLUT# - it
bounces, because it doesn't have ACK set and thus is not recognized as
applying to a connection which was already open.  It is either dropped
on the floor (deny policy) or bounced back to the outside system
(reject policy).  This does nobody any good, because the inside system
will continue to retransmit its next data packet periodically, each
retransmission will result in a RST, and none of the RST packets get
through.  The inside system will _never_ be informed that the
connection is dead.

The fix is relatively simple - treat packets with RST in their TCP
header just as if they had ACK.  A similar argument might be made for
FIN packets, I think, since it appears technically permissible to send
a FIN without an ACK, if a previous ACK had been sent and no window
change has occurred.  I haven't seen any of these show up, though, so
I'd guess that most/all TCP implementations do include a valid
sequence number and ACK bit in their FIN packets.

Here's a patch against 2.0.12 - it appears to be quite effective.  As
far as I've been able to think out, this should not open any avenues
for attacks which were not already possible.  I'd appreciate it if
people with more experience (and more paranoia) could consider this
issue and see if this is in fact an appropriate cure for the problem.

--- ip_fw.c.orig	Tue Aug 20 13:53:45 1996
+++ ip_fw.c	Tue Aug 20 13:54:08 1996
@@ -291,7 +291,7 @@
 			if (!offset) {
 				src_port=ntohs(tcp->source);
 				dst_port=ntohs(tcp->dest);
-				if(!tcp->ack)
+				if(!tcp->ack && !tcp->rst)
 					/* We do NOT have ACK, value TRUE */
 					notcpack=1;
 				if(!tcp->syn || !notcpack)


home help back first fref pref prev next nref lref last post