I recently ran across a problem with remote port forwarding in OpenSSH when
trying to use dynamic ports. While it is possible to use OpenSSH to request a
dynamic port and the OpenSSH sshd handles it just fine, the OpenSSH client gets
confused when multiple ports are opened this way, due to the information passed
in the "forwarded-tcpip" SSH_MSG_CHANNEL_OPEN message which is sent
back to the client when connections are opened. To illustrate this problem, I
tried the following with OpenSSH 6.2p1:
ssh -vvv -R 0:localhost:80 -R 0:localhost:81 localhost
In the debug output, I saw the lines:
debug1: remote forward success for: listen 0, connect localhost:80
Allocated port 60013 for remote forward to localhost:80
debug1: Updating allowed port 60013 for forwarding to host localhost port 80
debug1: remote forward success for: listen 0, connect localhost:81
Allocated port 60014 for remote forward to localhost:81
debug1: Updating allowed port 60014 for forwarding to host localhost port 81
So far, so good!
Connecting to port 60013 worked fine, causing the client to connect to
localhost:80 as requested, with the following debug output:
quad:~>debug1: client_input_channel_open: ctype forwarded-tcpip rchan 5 win
2097152 max 32768
debug1: client_request_forwarded_tcpip: listen localhost port 0, originator ::1
port 60153
debug2: fd 9 setting O_NONBLOCK
debug1: connect_next: host localhost ([::1]:80) in progress, fd=9
debug2: fd 9 setting TCP_NODELAY
debug3: fd 9 is O_NONBLOCK
debug3: fd 9 is O_NONBLOCK
debug1: channel 1: new [::1]
debug1: confirm forwarded-tcpip
debug3: channel 1: waiting for connection
debug1: channel 1: connected to localhost port 80
However, connecting to port 60014 did not work as expected. In that case, I saw:
debug1: client_input_channel_open: ctype forwarded-tcpip rchan 5 win 2097152 max
32768
debug1: client_request_forwarded_tcpip: listen localhost port 0, originator ::1
port 60182
debug2: fd 9 setting O_NONBLOCK
debug1: connect_next: host localhost ([::1]:80) in progress, fd=9
debug2: fd 9 setting TCP_NODELAY
debug3: fd 9 is O_NONBLOCK
debug3: fd 9 is O_NONBLOCK
debug1: channel 1: new [::1]
debug1: confirm forwarded-tcpip
debug3: channel 1: waiting for connection
debug1: channel 1: connected to localhost port 80
Note that even though this was to the second listening port I set up, the
connection was locally forwarded to port 80. The reason is that the
SSH_MSG_CHANNEL_OPEN of type "forwarded-tcpip" from sshd reported the
destination host & port as "localhost" port 0 for both the 60013
and 60014 connections, instead of reporting the actual listening port. The
client seems to expect the 0 value here and does the right thing when you only
have one dynamic listening port, but this breaks in the case where there are
multiple, since there's nothing in the SSH_MSG_CHANNEL_OPEN which
distinguishes between the two dynamic listeners. RFC 4254 is not completely
clear on what is expected in the message. It says:
When a connection comes to a port for which remote forwarding has
been requested, a channel is opened to forward the port to the other
side.
byte SSH_MSG_CHANNEL_OPEN
string "forwarded-tcpip"
uint32 sender channel
uint32 initial window size
uint32 maximum packet size
string address that was connected
uint32 port that was connected
string originator IP address
uint32 originator port
I was expecting "port that was connected" in this message to be the
dynamically allocated port so that it would always be a unique value, but this
is not the case (at least with OpenSSH's sshd). Instead, it always seems to
be the "port number to bind" value passed in the original
SSH_MSG_GLOBAL_REQUEST "tcpip-forward" message (which is 0 since
we're asking for a dynamic port).
Unfortunately, I would imagine changing this behavior on the server side might
break existing clients out there which are expecting to get this 0 value back in
channel open requests when they set up a dynamic listener, and I don't
really see a good way to resolve this. Does anyone have any suggestions?
--
Ron Frederick
ronf at timeheart.net
Ángel González
2013-Aug-16 00:14 UTC
Issue with OpenSSH remote forwarding of dynamic ports
On 08/08/13 06:22, Ron Frederick wrote:> When a connection comes to a port for which remote forwarding has > been requested, a channel is opened to forward the port to the other > side. > > byte SSH_MSG_CHANNEL_OPEN > string "forwarded-tcpip" > uint32 sender channel > uint32 initial window size > uint32 maximum packet size > string address that was connected > uint32 port that was connected > string originator IP address > uint32 originator port > > I was expecting "port that was connected" in this message to be the dynamically allocated port so that it would always be a unique value, but this is not the case (at least with OpenSSH's sshd). Instead, it always seems to be the "port number to bind" value passed in the original SSH_MSG_GLOBAL_REQUEST "tcpip-forward" message (which is 0 since we're asking for a dynamic port). > > Unfortunately, I would imagine changing this behavior on the server side might break existing clients out there which are expecting to get this 0 value back in channel open requests when they set up a dynamic listener, and I don't really see a good way to resolve this. Does anyone have any suggestions?It could pass 0 for the first forward and the real port in the next ones (which are already open), but IMHO the right thing would be to always provide the real port.
Maybe Matching Threads
- [Bug 2147] New: OpenSSH remote forwarding of dynamic ports doesn't work when you create more than one
- remote/reverse port forward, ssh client setting source IPs to what ssh server reports
- remote port forward failed because of failure resolving localhost to IP with error No such file or directory
- [Bug 2529] New: direct-streamlocal channel open doesn't match PROTOCOL documentation
- 'cancel-tcpip-forward' is not supported.