Troubleshooting SSH port forwarding
Content |
Objective
To diagnose problems related to SSH port forwarding
Symptoms
It is difficult to generalise about symptoms because they will depend on what protocol you are attempting to forward and what software you are using to send and receive that protocol. However, a useful distinction can be made between:
- failure to establish a connection, and
- issues that arise after a connection has been established.
The former could have almost any cause, whereas the latter suggests that the port forwarding mechanism itself is working. In that case you should consider:
- whether the software connecting through the port has been configured correctly, and
- whether the protocol in question is capable of being forwarded.
Investigation
Check that SSH is listening on the correct port
You can obtain a list of TCP ports that are open and listening using the netstat
command:
netstat -tln
It is not unusual to have several dozen open ports, but amongst them should be the one that SSH was asked to open (in this example port 8000):
Proto Recv-Q Send-Q Local Address Foreign Address State tcp 0 0 127.0.0.1:8000 0.0.0.0:* LISTEN
If the port is not open then this could be because:
- the wrong port number was requested (for example, by transposing the local and remote port numbers), or
- the port was already being used by another process, or
- the requested port is privileged and SSH did not have permission to listen on it, or
- the SSH client did not successfully connect to the server, or
- the SSH connection was made but has since been broken.
You can also see from the output of this command whether SSH has bound to the loopback address (127.0.0.1) or the wildcard address (0.0.0.0).
Check that you can connect to the final destination
A simple and reliable method for checking connectivity is to use netcat. For example:
nc -v 192.168.0.1 80
You should perform this test on the machine running the SSH client when using the -L
option to SSH, or on the machine running the SSH server when using the -R
option. The first argument is the machine to connect to and the second argument is the port number.
The reason for using the verbose option (-v
) is to distinguish between a connection that has been successfully opened and one where the server has not sent any response. In the former case you should see a response of the form:
www.private.example.com [192.168.0.1] 80 (www) open
whereas in the latter case there will be no output until the connection times out (which will typically take several minutes).
If you cannot make a connection then that could be because:
- the server at the final destination is not running, or
- access is blocked by a firewall, or
- you have specified the wrong port number, or
- the protocol uses UDP as opposed to TCP.
Even if netcat does make a connection, that does not necessarily prove that the service is usable. To do that your options include:
- connecting using client software designed to communicate using the relevant protocol (ideally the same client software that you intend to use with the forwarded port), or
- if the protocol is text-based and you are sufficiently familiar with it, attempting to converse in that protocol using netcat.
An example of the former would be fetching a page from a webserver using wget
:
wget http://www.private.example.com/
An example of the latter would be to issue an HTTP command after netcat has connected:
GET /
It may very well be that neither of these options is feasible, however this is a worthwhile test if you are able to perform it.
Enable debug logging on the SSH server
The log level can be changed to DEBUG
by altering the LogLevel
directive in the SSH server configuration file (typically /etc/ssh/sshd_config
):
LogLevel DEBUG1
Restart the SSH server, then establish an SSH connection with port forwarding enabled, for example:
ssh -L 127.0.0.1:8000:192.168.0.1:80 ssh.example.com
from client to server or:
ssh -R 127.0.0.1:8631:127.0.0.1:631 ssh.example.com
from server to client. Finally, attempt to make a TCP connection through SSH using netcat, for example:
nc -v 127.0.0.1 8000
Where the log is sent will depend on the configuration of SSH and syslog, but /var/log/auth.log
would be typical. In it you should see a series of messages similar to:
debug1: server_input_channel_open: ctype direct-tcpip rchan 2 win 2097152 max 32768 debug1: server_request_direct_tcpip: originator 127.0.0.1 port 39237, target 192.168.0.1 port 80 debug1: connect_next: host 192.168.0.1 ([192.168.0.1]:80) in progress, fd=8 debug1: channel 2: new [direct-tcpip] debug1: server_input_channel_open: confirm direct-tcpip debug1: channel 2: connected to 192.168.0.1 port 80
if the netcat connection is from client to server or:
debug1: Connection to port 8631 forwarding to 127.0.0.1 port 0 requested. debug1: channel 3: new [forwarded-tcpip] debug1: channel 3: free: forwarded-tcpip: listening port 8631 for 127.0.0.1 port 0, connect from 127.0.0.1 port 46371, nchannels 4
if the connection is from the server to the client. If you don't see anything then that could indicate that:
- you have not successfully changed the
LogLevel
, or - the process that netcat is connecting to is not SSH.
You can check the LogLevel
by looking for other messages prefixed with debug1
: they should be very numerous.
If the connection is being accepted by some other process then that will have prevented SSH from listening on the specified port. In that case the simplest solution is to choose another port.
Remember to restore the LogLevel
to its previous value (typically INFO
).
Perform an end-to-end connectivity test using netcat
If the SSH log indicates that the port is being forwarded, but you are still unable to connect through it in the desired manner, it may be helpful to perform an end-to-end test using netcat.
Ideally this should be done using the same remote address and port number that you ultimately want to connect to. In that case you will need to temporarily stop the server that would normally be listening on the port before starting netcat. If this is not feasible then you will need to use a different port, or a different address, or both.
Use the -l
option to run netcat as a server on the machine that is the final destination of the connection:
nc -l -p 80
Now try connecting, again using netcat, from the machine on which the connection is to originate:
nc 127.0.0.1 8000
Any lines that you type into the client should be displayed by the server and vice versa.
If this test succeeds then you will have established that SSH is correctly forwarding the port. In that case you should investigate:
- whether the protocol in question is capable of being forwarded, and
- whether the port that has been forwarded is the one required by the protocol.
You may also want to double-check that you can successfully connect from the machine running the SSH server to the final destination.
See also
- Forward a TCP port from an SSH client to an SSH server
- Forward a TCP port from an SSH server to an SSH client
Tags: ssh