Work around Linux kernel bug provoked by nchan.c

Zack Weinberg zack at wolery.cumb.org
Mon Jul 24 03:03:23 EST 2000


The Linux implementation of TCP sockets has a bug which causes
shutdown(sock, SHUT_RD) to fail spuriously (ENOTCONN) if the write
side of the socket has already been shut down.  If you are using SSH
port forwarding to tunnel HTTP through a firewall, nchan.c will tickle
this bug once for every HTTP exchange.  You will therefore get lots of
useless, annoying error messages:

channel 2: chan_shutdown_read: shutdown() failed for fd7 [i1 o128]: Transport endpoint is not connected

Here's a complete debugging trace of one such forwarded channel.  This
is SSH1 protocol; I haven't got the setup to do SSH2 yet.  The remote
server is 2.0.12 F-SECURE SSH on Solaris 2.6; I am using openssh
2.1.1p4 with kernel 2.2.16.

debug: channel 2: new [listen port 3128 for webcache.example.com port 3128, connect from localhost port 1817]
debug: channel 2: rcvd ieof
debug: channel 2: output open -> drain
debug: channel 2: obuf empty
debug: channel 2: output drain -> closed
debug: channel 2: send oclose
debug: channel 2: close_write
debug: channel 2: read<=0 rfd 7 len 0
debug: channel 2: read failed
debug: channel 2: input open -> drain
debug: channel 2: close_read
channel 2: chan_shutdown_read: shutdown() failed for fd7 [i1 o128]: Transport endpoint is not connected
debug: channel 2: input: no drain shortcut
debug: channel 2: ibuf empty
debug: channel 2: input drain -> wait_oclose
debug: channel 2: send ieof
debug: channel 2: rcvd oclose
debug: channel 2: input wait_oclose -> closed
debug: channel 2: full closed

I'd appreciate it if the appended patch could be applied.  It causes
ssh to recognize the bug and not emit the error message.

[I've reported the bug to the kernel developers but they do not seem
interested in fixing it.]

zw

--- openssh-2.1.1p4.orig/nchan.c	Thu Jun 22 04:32:31 2000
+++ openssh-2.1.1p4/nchan.c	Sun Jul 23 09:42:23 2000
@@ -483,7 +483,12 @@
 		return;
 	debug("channel %d: close_read", c->self);
 	if (c->sock != -1) {
-		if (shutdown(c->sock, SHUT_RD) < 0)
+		/* shutdown(sock, SHUT_READ) may return ENOTCONN if the
+		   write side has been closed already.  */
+		if (shutdown(c->sock, SHUT_RD) < 0
+		    && (errno != ENOTCONN
+			|| c->ostate == CHAN_OUTPUT_OPEN
+			|| c->ostate == CHAN_OUTPUT_WAIT_DRAIN))
 			error("channel %d: chan_shutdown_read: shutdown() failed for fd%d [i%d o%d]: %.100s",
 			    c->self, c->sock, c->istate, c->ostate, strerror(errno));
 	} else {





More information about the openssh-unix-dev mailing list