ssh: check if a tunnel is alive
Asked Answered
L

10

49

I have written a small bash script which needs an ssh tunnel to draw data from a remote server, so it prompts the user:

echo "Please open an ssh tunnel using 'ssh -L 6000:localhost:5432 example.com'"

I would like to check whether the user had opened this tunnel, and exit with an error message if no tunnel exist. Is there any way to query the ssh tunnel, i.e. check if the local port 6000 is really tunneled to that server?

Lightish answered 4/1, 2010 at 8:49 Comment(1)
this might partially help "lsof -i | grep ssh"Presnell
B
37

This is my test. Hope it is useful.

# $COMMAND is the command used to create the reverse ssh tunnel
COMMAND="ssh -p $SSH_PORT -q -N -R $REMOTE_HOST:$REMOTE_HTTP_PORT:localhost:80 $USER_NAME@$REMOTE_HOST"

# Is the tunnel up? Perform two tests:

# 1. Check for relevant process ($COMMAND)
pgrep -f -x "$COMMAND" > /dev/null 2>&1 || $COMMAND

# 2. Test tunnel by looking at "netstat" output on $REMOTE_HOST
ssh -p $SSH_PORT $USER_NAME@$REMOTE_HOST netstat -an | egrep "tcp.*:$REMOTE_HTTP_PORT.*LISTEN" \
   > /dev/null 2>&1
if [ $? -ne 0 ] ; then
   pkill -f -x "$COMMAND"
   $COMMAND
fi
Borderland answered 4/1, 2010 at 9:7 Comment(1)
Looks like there's a bug in the above code. if [ $? -ne 0 ], the 0 should probably be a 1. the remote egrep will set $? to 0 if it successfully finds a match. In any event, I needed to use 1 to get this command to stop killing the existing tunnel every time I ran the command.Newfashioned
J
89

Netcat is your friend:

nc -z localhost 6000 || echo "no tunnel open"
Javelin answered 22/6, 2014 at 21:40 Comment(2)
Wow, that's damn useful. I'm making a script that first of all creates a ssh tunnel, and I'm now using netcat to know when it's ready to accept connections. Works like a charm.Aristotle
I would also suggest to use nc -zv to get Connection to localhost (127.0.0.1) 6000 port [tcp/*] succeeded! instead of no message upon successful connectionArabesque
B
37

This is my test. Hope it is useful.

# $COMMAND is the command used to create the reverse ssh tunnel
COMMAND="ssh -p $SSH_PORT -q -N -R $REMOTE_HOST:$REMOTE_HTTP_PORT:localhost:80 $USER_NAME@$REMOTE_HOST"

# Is the tunnel up? Perform two tests:

# 1. Check for relevant process ($COMMAND)
pgrep -f -x "$COMMAND" > /dev/null 2>&1 || $COMMAND

# 2. Test tunnel by looking at "netstat" output on $REMOTE_HOST
ssh -p $SSH_PORT $USER_NAME@$REMOTE_HOST netstat -an | egrep "tcp.*:$REMOTE_HTTP_PORT.*LISTEN" \
   > /dev/null 2>&1
if [ $? -ne 0 ] ; then
   pkill -f -x "$COMMAND"
   $COMMAND
fi
Borderland answered 4/1, 2010 at 9:7 Comment(1)
Looks like there's a bug in the above code. if [ $? -ne 0 ], the 0 should probably be a 1. the remote egrep will set $? to 0 if it successfully finds a match. In any event, I needed to use 1 to get this command to stop killing the existing tunnel every time I ran the command.Newfashioned
B
23

Autossh is best option - checking process is not working in all cases (e.g. zombie process, network related problems)

example:

autossh -M 2323 -c arcfour -f -N -L 8088:localhost:80 host2
Buxtehude answered 19/10, 2010 at 13:46 Comment(0)
E
12

This is really more of a serverfault-type question, but you can use netstat.

something like:

 # netstat -lpnt | grep 6000 | grep ssh

This will tell you if there's an ssh process listening on the specified port. it will also tell you the PID of the process.

If you really want to double-check that the ssh process was started with the right options, you can then look up the process by PID in something like

# ps aux | grep PID
Eustoliaeutectic answered 4/1, 2010 at 9:6 Comment(1)
Note that this solution doesn't work on OS X, because netstat on OS X is different.Thirteen
P
8

Use autossh. It's the tool that's meant for monitoring the ssh connection.

Phlogistic answered 17/8, 2010 at 19:24 Comment(0)
Y
4

We can check using ps command

# ps -aux | grep ssh

Will show all shh service running and we can find the tunnel service listed

Yusuk answered 16/1, 2018 at 14:38 Comment(0)
F
3

These are more detailed steps to test or troubleshoot an SSH tunnel. You can use some of them in a script. I'm adding this answer because I had to troubleshoot the link between two applications after they stopped working. Just grepping for the ssh process wasn't enough, as it was still there. And I couldn't use nc -z because that option wasn't available on my incantation of netcat.

Let's start from the beginning. Assume there is a machine, which will be called local with IP address 10.0.0.1 and another, called remote, at 10.0.3.12. I will prepend these hostnames, to the commands below, so it's obvious where they're being executed.

The goal is to create a tunnel that will forward TCP traffic from the loopback address on the remote machine on port 123 to the local machine on port 456. This can be done with the following command, on the local machine:

local:~# ssh -N -R 123:127.0.0.1:456 10.0.3.12

To check that the process is running, we can do:

local:~# ps aux | grep ssh

If you see the command in the output, we can proceed. Otherwise, check that the SSH key is installed in the remote. Note that excluding the username before the remote IP, makes ssh use the current username.

Next, we want to check that the tunnel is open on the remote:

remote:~# netstat | grep 10.0.0.1

We should get an output similar to this:

tcp  0  0  10.0.3.12:ssh  10.0.0.1:45988  ESTABLISHED

Would be nice to actually see some data going through from the remote to the host. This is where netcat comes in. On CentOS it can be installed with yum install nc.

First, open a listening port on the local machine:

local:~# nc -l 127.0.0.1:456

Then make a connection on the remote:

remote:~# nc 127.0.0.1 123

If you open a second terminal to the local machine, you can see the connection. Something like this:

local:~# netstat | grep 456
tcp  0  0 localhost.localdom:456 localhost.localdo:33826 ESTABLISHED
tcp  0  0 localhost.localdo:33826 localhost.localdom:456 ESTABLISHED

Better still, go ahead and type something on the remote:

remote:~# nc 127.0.0.1 8888
Hallo?
anyone there?

You should see this being mirrored on the local terminal:

local:~# nc -l 127.0.0.1:456
Hallo?
anyone there?

The tunnel is working! But what if you have an application, called appname, which is supposed to be listening on port 456 on the local machine? Terminate nc on both sides then run your application. You can check that it's listening on the correct port with this:

local:~# netstat -tulpn | grep LISTEN | grep appname
tcp  0  0  127.0.0.1:456  0.0.0.0:* LISTEN  2964/appname

By the way, running the same command on the remote should show sshd listening on port 127.0.0.1:123.

Famish answered 3/11, 2017 at 21:3 Comment(0)
L
2
#!/bin/bash

# Check do we have tunnel to example.com server
lsof -i tcp@localhost:6000 > /dev/null

# If exit code wasn't 0 then tunnel doesn't exist.
if [ $? -eq 1 ]
then
  echo ' > You missing ssh tunnel. Creating one..'
  ssh -L 6000:localhost:5432 example.com
fi

echo ' > DO YOUR STUFF < '
Leshalesher answered 22/9, 2017 at 10:43 Comment(0)
W
1

stunnel is a good tool to make semi-permanent connections between hosts.

http://www.stunnel.org/

Willywilly answered 22/9, 2012 at 18:3 Comment(0)
H
0

If you are using ssh in background, use this:

sudo lsof -i -n | egrep '\<ssh\>'
Heteropolar answered 14/3, 2019 at 20:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.