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.
Possibly Parallel 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.