From michiel@boland.org  Mon Oct 11 07:38:21 2004
Return-Path: <michiel@boland.org>
Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125])
	by hub.freebsd.org (Postfix) with ESMTP id BBDD916A4CE
	for <FreeBSD-gnats-submit@freebsd.org>; Mon, 11 Oct 2004 07:38:21 +0000 (GMT)
Received: from smtp-vbr9.xs4all.nl (smtp-vbr9.xs4all.nl [194.109.24.29])
	by mx1.FreeBSD.org (Postfix) with ESMTP id 4182243D1D
	for <FreeBSD-gnats-submit@freebsd.org>; Mon, 11 Oct 2004 07:38:21 +0000 (GMT)
	(envelope-from michiel@boland.org)
Received: from xs6.xs4all.nl (xs6.xs4all.nl [194.109.21.6])
	by smtp-vbr9.xs4all.nl (8.12.11/8.12.11) with ESMTP id i9B7cKIa026268
	for <FreeBSD-gnats-submit@freebsd.org>; Mon, 11 Oct 2004 09:38:20 +0200 (CEST)
	(envelope-from michiel@boland.org)
Received: from xs6.xs4all.nl (boland37@localhost.xs4all.nl [127.0.0.1])
	by xs6.xs4all.nl (8.12.10/8.12.10) with ESMTP id i9B7cKXC079710
	for <FreeBSD-gnats-submit@freebsd.org>; Mon, 11 Oct 2004 09:38:20 +0200 (CEST)
	(envelope-from michiel@boland.org)
Received: (from boland37@localhost)
	by xs6.xs4all.nl (8.12.10/8.12.9/Submit) id i9B7cKIN079709
	for FreeBSD-gnats-submit@freebsd.org; Mon, 11 Oct 2004 09:38:20 +0200 (CEST)
	(envelope-from michiel@boland.org)
Message-Id: <200410110738.i9B7cKIN079709@xs6.xs4all.nl>
Date: Mon, 11 Oct 2004 09:38:20 +0200 (CEST)
From: Michiel Boland <michiel@boland.org>
To: FreeBSD-gnats-submit@freebsd.org
Subject: TCP should honour incoming RSTs even if the receive window is closed
X-Send-Pr-Version: 3.113
X-GNATS-Notify:

>Number:         72502
>Category:       kern
>Synopsis:       [patch] TCP should honour incoming RSTs even if the receive window is closed
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    silby
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Mon Oct 11 07:40:28 GMT 2004
>Closed-Date:    Fri Jan 28 08:38:59 GMT 2005
>Last-Modified:  Fri Jan 28 08:38:59 GMT 2005
>Originator:     Michiel Boland
>Release:        FreeBSD 6.0-CURRENT i386
>Organization:
>Environment:
System: FreeBSD leefnet.office.internl.net 6.0-CURRENT FreeBSD 6.0-CURRENT #0: Sat Oct 9 15:53:21 CEST 2004 root@leefnet.office.internl.net:/usr/obj/usr/src/sys/LEEFNET i386


	
>Description:
TCP should honour incoming RST segments, even if the receive window is closed.
(See RFC793, page 26.)
Currently, FreeBSD drops RST packets on the floor, which may cause applications
to hang indefinitely.
>How-To-Repeat:
The following code sets up two connected TCP sockets that send data to each
other until the window is closed. Then one of the sockets is closed, which
will generate a RST once the TCP at the other socket does a window probe.
But the RST is ignored, therefore the application will never exit.
After applying the patch below, the app will exit after a couple of seconds.
(FWIW Linux 2.4 and Solaris 7-9 do this correctly.)

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <poll.h>
#include <unistd.h>
#include <string.h>

int main(void)
{
	int o, s, t, u, do_t, do_u;
	struct pollfd pfd[2];
	struct sockaddr_in sa;
	char buf[4096];

	s = socket(AF_INET, SOCK_STREAM, 0);
	if (s == -1)
		return 1;
	o = 1;
	setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &o, sizeof o);
	memset(&sa, 0, sizeof sa);
	sa.sin_family = AF_INET;
	sa.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
	sa.sin_port = htons(3737);
	if (bind(s, (struct sockaddr *) &sa, sizeof sa) == -1)
		return 1;
	if (listen(s, 1) == -1)
		return 1;
	t = socket(AF_INET, SOCK_STREAM, 0);
	if (t == -1)
		return 1;
	if (connect(t, (struct sockaddr *) &sa, sizeof sa) == -1)
		return 1;
	u = accept(s, 0, 0);
	if (u == -1)
		return 1;
	close(s);
	fcntl(t, F_SETFL, fcntl(t, F_GETFL) | O_NONBLOCK);
	fcntl(u, F_SETFL, fcntl(t, F_GETFL) | O_NONBLOCK);
	do_t = 1;
	do_u = 1;
	pfd[0].fd = t;
	pfd[0].events = POLLOUT;
	pfd[1].fd = u;
	pfd[1].events = POLLOUT;
	while (do_t || do_u) {
		if (poll(pfd, 2, 1000) == 0) {
			close(t);
			pfd[0].fd = -1;
			do_t = 0;
			continue;
		}
		if (pfd[0].revents & POLLOUT) {
			if (write(t, buf, sizeof buf) == -1) {
				close(t);
				pfd[0].fd = -1;
				do_t = 0;
			}
		}
		if (pfd[1].revents & POLLOUT) {
			if (write(u, buf, sizeof buf) == -1) {
				close(u);
				pfd[1].fd = -1;
				do_u = 0;
			}
		}
	}
	return 0;
}

>Fix:

Apply the following patch to src/sys/netinet/tcp_input.c

--- tcp_input.c.orig	Tue Oct  5 20:36:23 2004
+++ tcp_input.c	Mon Oct 11 01:32:17 2004
@@ -1622,8 +1622,9 @@
 	 *      RFC 1337.
 	 */
 	if (thflags & TH_RST) {
-		if (SEQ_GEQ(th->th_seq, tp->last_ack_sent) &&
-		    SEQ_LT(th->th_seq, tp->last_ack_sent + tp->rcv_wnd)) {
+		if ((SEQ_GEQ(th->th_seq, tp->last_ack_sent) &&
+		    SEQ_LT(th->th_seq, tp->last_ack_sent + tp->rcv_wnd)) ||
+		    (tp->rcv_wnd == 0 && tp->last_ack_sent == th->th_seq)) {
 			switch (tp->t_state) {
 
 			case TCPS_SYN_RECEIVED:

>Release-Note:
>Audit-Trail:
Responsible-Changed-From-To: freebsd-bugs->freebsd-net 
Responsible-Changed-By: arved 
Responsible-Changed-When: Fri Nov 19 12:02:29 GMT 2004 
Responsible-Changed-Why:  
over to freebsd-net mailinglist for review 

http://www.freebsd.org/cgi/query-pr.cgi?pr=72502 
Responsible-Changed-From-To: freebsd-net->silby 
Responsible-Changed-By: silby 
Responsible-Changed-When: Fri Nov 26 08:09:32 GMT 2004 
Responsible-Changed-Why:  
Patch committed, hook into the regression test framework and MFCs still 
pending. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=72502 
State-Changed-From-To: open->closed 
State-Changed-By: silby 
State-Changed-When: Fri Jan 28 08:38:33 GMT 2005 
State-Changed-Why:  
This has all been committed, including the regression test. 

Once again, thanks for the great bug report! 

http://www.freebsd.org/cgi/query-pr.cgi?pr=72502 
>Unformatted:
