Issue with OpenSSH remote forwarding of dynamic ports

Ron Frederick ronf at timeheart.net
Thu Aug 8 14:22:56 EST 2013


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





More information about the openssh-unix-dev mailing list