List open SSH tunnels

71

36

I use a lot of SSH tunnels to various servers on my linux machine (for tunnelling to databases, web servers etc) and it would be really handy to view a list of current open tunnels via a shell script.

I can identify local connections via a grep on netstat along the lines of:

netstat -n --protocol inet | grep ':22'

but this won't show me the remote port its connected to (and obviously includes standard SSH connections that aren't tunnelled)

UPDATE: The answers are fine but are not showing me the remote port I'm connected to. E.g I often have a tunnel through to mysql, say localhost:3308 mapping to :3306 on the server. Normally I can guess by the local ports I've chosen but would be nice to have access to both.

Any ideas?

James Frost

Posted 2011-02-21T11:09:34.637

Reputation: 813

4I've seen a couple questions like this recently (not specifically what you are asking), but related to ssh providing information about the connection. As cool as ssh is, it sucks at providing some basic useful information like that. There are some client internal commands you can run like <ret><ret> ~# and the $SSH_CONNECTION environment variable, but they really are sparse on details. A list of running tunnels would be nice. Maybe its time for a feature request. – deltaray – 2011-02-22T02:31:53.177

Answers

82

if you only want to list tunnels created by ssh:

% sudo lsof -i -n | egrep '\<ssh\>'
ssh  19749  user  3u  IPv4 148088244   TCP x.x.x.x:39689->y.y.y.y:22 (ESTABLISHED)
ssh  19749  user  4u  IPv6 148088282   TCP [::1]:9090 (LISTEN)
ssh  19749  user  5u  IPv4 148088283   TCP 127.0.0.1:9090 (LISTEN)

(that would be a -L 9090:localhost:80 tunnel)

if you want to see the tunnels / connections made to a sshd:

 % sudo lsof -i -n | egrep '\<sshd\>'
sshd  15767  root  3u  IPv4 147401205   TCP x.x.x.x:22->y.y.y.y:27479 (ESTABLISHED)
sshd  15842  user  3u  IPv4 147401205   TCP x.x.x.x:22->y.y.y.y:27479 (ESTABLISHED)
sshd  15842  user  9u  IPv4 148002889   TCP 127.0.0.1:33999->127.0.0.1:www (ESTABLISHED)
sshd  1396   user  9u  IPv4 148056581   TCP 127.0.0.1:5000 (LISTEN)
sshd  25936  root  3u  IPv4 143971728   TCP *:22 (LISTEN)

the ssh-daemon listens on port 22 (last line), 2 subprocesses are spawned (first 2 lines, login of 'user'), a -R tunnel created on port 5000, and a -L tunnel which forwards a port from my (local) machine to localhost:80 (www).

akira

Posted 2011-02-21T11:09:34.637

Reputation: 52 754

The 3rd line is only there because the TCP socket is in use. It just says the something through a ssh tunnel has hit your local web server, not that the 33999 port is forwarded to the 80 one. – shellholic – 2011-02-21T13:02:26.413

thats the essence of a -L tunnel... – akira – 2011-02-21T13:03:37.053

That's fine, its showing the remote IP address and the list of tunnelled ports. What I ideally want to know is what the remote port its tunnelled to. For example, if I've got a tunnel open from 3308 locally to 3306 on the server I want to see both. – James Frost – 2011-02-23T10:33:24.787

for that you would have to either login to the server and execute the sshd-related lsof there (reliable) or parse the output of /proc/PID/cmdline for all of your ssh-commands .. which might give you misleading results since you can specify tunnels via .ssh/config as well. – akira – 2011-02-23T11:06:11.780

Yep, makes sense. Need to be a bit cleverer with the script then to parse the results, get a list of remote servers and execute the same command on each to retrieve the remote ports. Definitely doable. Will get on it! – James Frost – 2011-03-02T09:49:03.217

16

Try this command, it might be useful:

ps aux | grep ssh

Rajesh

Posted 2011-02-21T11:09:34.637

Reputation: 169

my suggestion would be: ps aux | grep [s]shd – CousinCocaine – 2014-02-27T08:54:47.183

16

not exactly the solution for your problem, but also handy sometimes:

From within an ssh session:

  1. press enter
  2. type ~ and then #

shows you a list of all open connections over your tunnels for that session.

reto

Posted 2011-02-21T11:09:34.637

Reputation: 416

2That works only for interactive tunnels (without -N and -f, …), but interesting to know. – erik – 2014-03-13T23:35:30.140

7

netstat -tpln | grep ssh
  • t: TCP
  • p: show process
  • l: listening
  • n: numeric values

EDIT: example for @akira comment:

(header added, tested on Debian wheezy)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 127.0.0.1:1443          0.0.0.0:*               LISTEN      4036/ssh        

Which can be read as: SSH (not SSHd) is listening to local TCP port 1443.

shellholic

Posted 2011-02-21T11:09:34.637

Reputation: 8 177

Also note that -p shows only your own processes (all processes by root). Also, that command shows sshd too. – Olli – 2011-02-21T12:11:32.200

for -R tunnels you have to avoid -l – akira – 2011-02-21T13:16:33.117

You can't see locally the -R tunnels if not in use. But right, if in use, you can catch them without the -l – shellholic – 2011-02-21T13:26:29.723

5

This is the top google result for this question, so I will put my answer here. I stayed up all night filtering the results, and came up with a long complex command that shows you only your reverse ssh tunnels in this format:

publicipaddress:remoteforwardedport

Here is the code, I am running Ubuntu Server 12. I am running reverse ssh tunnels that forward local port 5900 to my public ssh server, and this nifty command shows all my public ip addresses with the remote port.

sudo lsof -i -n | egrep '\<sshd\>' | grep -v ":ssh" | grep LISTEN | sed 1~2d | awk '{ print $2}' | while read line; do sudo lsof -i -n | egrep $line | sed 3~3d | sed 's/.*->//' | sed 's/:......*(ESTABLISHED)//' | sed 's/.*://' | sed 's/(.*//' | sed 'N;s/\n/:/' 2>&1 ;done

Brandon

Posted 2011-02-21T11:09:34.637

Reputation: 51

2

report_local_port_forwardings() {

  # -a ands the selection criteria (default is or)
  # -i4 limits to ipv4 internet files
  # -P inhibits the conversion of port numbers to port names
  # -c /regex/ limits to commands matching the regex
  # -u$USER limits to processes owned by $USER
  # http://man7.org/linux/man-pages/man8/lsof.8.html
  # https://stackoverflow.com/q/34032299

  echo 
  echo "LOCAL PORT FORWARDING"
  echo
  echo "You set up the following local port forwardings:"
  echo

  lsof -a -i4 -P -c '/^ssh$/' -u$USER -s TCP:LISTEN

  echo
  echo "The processes that set up these forwardings are:"
  echo

  ps -f -p $(lsof -t -a -i4 -P -c '/^ssh$/' -u$USER -s TCP:LISTEN)

}

report_remote_port_forwardings() {

  echo 
  echo "REMOTE PORT FORWARDING"
  echo
  echo "You set up the following remote port forwardings:"
  echo

  ps -f -p $(lsof -t -a -i -c '/^ssh$/' -u$USER -s TCP:ESTABLISHED) | awk '
  NR == 1 || /R (\S+:)?[[:digit:]]+:\S+:[[:digit:]]+.*/
  '
}

report_local_port_forwardings
report_remote_port_forwardings

Sample output:

LOCAL PORT FORWARDING

You set up the following local port forwardings:

COMMAND   PID  USER   FD   TYPE  DEVICE SIZE/OFF NODE NAME
ssh     10086 user     7u  IPv4 1924960      0t0  TCP localhost:2301 (LISTEN)
ssh     10086 user     9u  IPv4 1924964      0t0  TCP localhost:2380 (LISTEN)
ssh     10086 user    11u  IPv4 1924968      0t0  TCP localhost:2381 (LISTEN)

The processes that set up these forwardings are:

UID        PID  PPID  C STIME TTY          TIME CMD
user     10086  7074  0 13:05 pts/21   00:00:00 ssh -N ssh.example.com

REMOTE PORT FORWARDING

You set up the following remote port forwardings:

UID        PID  PPID  C STIME TTY      STAT   TIME CMD
user      7570 30953  0 11:14 pts/18   S      0:00 ssh -N -R 9000:localhost:3000 ssh.example.com

Robin A. Meade

Posted 2011-02-21T11:09:34.637

Reputation: 141

0

Since I don't like lsof, I suggest an alternative method (another guy taught me :)):

$ netstat -l | grep ssh

In this way you show the ssh tunnels created by ssh that are opened in LISTEN mode (and are omitted by default by netstat).

FSp

Posted 2011-02-21T11:09:34.637

Reputation: 101

0

/sbin/ip tunnel list # replacement for the deprecated iptunnel command

Lucas Cimon

Posted 2011-02-21T11:09:34.637

Reputation: 373

0

#!/bin/csh -f
echo SSH Tunnels Connected
echo
foreach f (`netstat -an -p | grep tcp | grep sshd | grep -v :: | grep -v 0:22 | grep LISTEN | cut -d" " -f45- | cut -d"/" -f1`)
set ip = `netstat -an -p | grep tcp | grep sshd | grep -v :: | grep -v 0:22 | grep ESTABLISH | grep $f | cut -d" " -f20- | cut -d":" -f1`
#set h = `grep -a "$ip" /htdocs/impsip.html | grep br | cut -d" " -f2`
echo -n "$ip    "
echo  `netstat -an -p | grep tcp | grep sshd | grep -v :: | grep -v 0:22 | grep LISTEN | grep $f | cut -d":" -f2  | cut -d" " -f1`
#echo  " $h"
end

Richard

Posted 2011-02-21T11:09:34.637

Reputation: 1