I have found a problem with port forwarding on Mac OS X (10.2 and
10.3). When I forward
a port to localhost, as in
ssh -R 40404:localhost:40404 somehost
...and the remote system makes a connection on this port, I get the
message
getsockopt TCP_NODELAY: Connection reset by peer
I have tracked this down to the loop in connect_to that gets a list of
addresses from
getaddrinfo and tries them one after another. When "localhost" is the
host name.
getaddrinfo returns an IPv6 address, followed by an IPv4 address. The
loop is
designed to try connections until it finds one that works.
Unfortunately, on my system,
the IPv6 connection returns EINPROGRESS, which is interpreted as
success. This
causes the retry loop to exit, and the next thing that happens is a
call to set_nodelay
which fails when the IPv6 connection is not available.
I think it would be better to put the call to set_nodelay inside the
retry loop. Then if the
call fails for IPv6, ssh can revert to IPv4. Of course, the error
report in the call to
set_nodelay would have to be suppressed is the connection was going to
be retried,
and the function would need to return a value to indicate success or
failure.
A fix seems relatively straightforward, but I would rather not attempt
to write the patch
myself, since changing the way set_nodelay reports errors would affect
other routines
that call it, and I am not familiar enough with them to mess around
there.
Two workarounds for this problem are: 1) force only IPv4 connections by
setting -4 on
the command line or the corresponding option in the config file.
However, this isn't
portable to other ssh versions, and my code needs to work with them. 2)
specify the
local host as "127.0.0.1" instead of "localhost". This is
what I'm
doing, and it seems to
work.
John