Tobias Ringstrom
2001-Jul-02 17:28 UTC
Forwarding race resulting in lost data in openssh-2.9p2
When a TCP connection is established through a tunnel (e.g. using -L 2000:www.openssh.org:80), all data sent by the local TCP client is silently dropped until the sshd has opened the connection to the remote (www.openssh.org). This is very visible when forwarding to a remote host that is far away (i.e. has high ping time) from the sshd. I have attached a sample program that shows the problem. To reproduce the problem, run the following: [server] sshd [client window 1] slogin -L 2000:www.openssh.org:80 server [client window 2] gcc get.c -o get [client window 2] ./get 5 (no problem, takes time) [client window 2] ./get (hangs forever) After the attached patch, which may or may not be correct, the problem goes away. Even if the patch is not correct, it clearly illustrates what the problem is, namely that sshd silently drops data when in the CONNECTING state (and other states too, possibly). (I'm not on the list, so please CC any replies to me.) /Tobias -------------- next part -------------- #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <netinet/in.h> #include <netinet/tcp.h> #include <string.h> #include <sys/socket.h> #include <arpa/inet.h> int main(int argc, char *argv[]) { struct sockaddr_in remoteAddr; int sock, delay = 0, n; char buf[1024]; if (argc > 1) delay = atoi(argv[1]); memset(&remoteAddr, 0, sizeof(&remoteAddr)); remoteAddr.sin_family = AF_INET; remoteAddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); remoteAddr.sin_port = htons(8000); sock = socket(AF_INET, SOCK_STREAM, 0); if (sock == -1) abort(); if (connect(sock, (struct sockaddr*)&remoteAddr, sizeof(remoteAddr)) == -1) abort(); if (delay) sleep(delay); write(sock, "GET /\n\n", 7); while ((n = read(sock, buf, sizeof(buf))) > 0) write(1, buf, n); close(sock); return 0; } -------------- next part -------------- --- channels.c.orig Wed Jun 13 21:18:05 2001 +++ channels.c Mon Jul 2 19:00:09 2001 @@ -1302,7 +1302,8 @@ /* Ignore any data for non-open channels (might happen on close) */ if (c->type != SSH_CHANNEL_OPEN && - c->type != SSH_CHANNEL_X11_OPEN) + c->type != SSH_CHANNEL_X11_OPEN && + c->type != SSH_CHANNEL_CONNECTING) return; /* same for protocol 1.5 if output end is no longer open */