Bash script to setup a temporary SSH tunnel

2019-01-20 21:02发布

On CYGWIN, I want a BASH script to:

  1. create an SSH tunnel to a remote server.
  2. Do some work locally that uses the tunnel.
  3. Then shutdown the tunnel.

The "shutdown part" has me perplexed.

Currently, I have a lame solution. In one shell I run the following to create a tunnel.

# Create the tunnel - this works! It runs forever, until shell is quit.
ssh -nNT -L 50000:localhost:3306 jm@sampledomain.com

Then, in another shell window, I do my work

# Do some MYSQL stuff over local port 50000 (which goes to remote port 3306)

Finally, when I am done. I close the first shell window to kill the tunnel.

I'd like to do this all in one script like: # Create tunnel # do work # Kill tunnel

How do I keep track of the tunnel process, so I know which one to kill?

标签: bash ssh
6条回答
霸刀☆藐视天下
2楼-- · 2019-01-20 21:44

You can tell SSH to background itself with the -f option but you won't get the PID with $!. Also instead of having your script sleep an arbitrary amount of time before you use the tunnel, you can use -o ExitOnForwardFailure=yes with -f and SSH will wait for all remote port forwards to be successfully established before placing itself in the background. You can grep the output of ps to get the PID. For example you can use

...
ssh -Cfo ExitOnForwardFailure=yes -NL 9999:localhost:5900 $REMOTE_HOST
PID=$(pgrep -f 'NL 9999:')
[ "$PID" ] || exit 1
...

and be pretty sure you're getting the desired PID

查看更多
聊天终结者
3楼-- · 2019-01-20 21:49

You can do this cleanly with an ssh 'control socket'. To talk to an already-running SSH process and get it's pid, kill it etc. Use the 'control socket' (-M for master and -S for socket) as follows:

$ ssh -M -S my-ctrl-socket -fnNT -L 50000:localhost:3306 jm@sampledomain.com
$ ssh -S my-ctrl-socket -O check jm@sampledomain.com
Master running (pid=3517) 
$ ssh -S my-ctrl-socket -O exit jm@sampledomain.com
Exit request sent. 

Note that my-ctrl-socket will be an actual file that is created.

I got this info from a very RTFM reply on the OpenSSH mailing list.

查看更多
迷人小祖宗
4楼-- · 2019-01-20 21:51

I prefer to launch a new shell for separate tasks and I often use the following command combination:

  $ sudo bash; exit

or sometimes:

  $ : > sensitive-temporary-data.txt; bash; rm -f sensitive-temporary-data.txt; exit

These commands create a nested shell where I can do all my work; when I'm finished I hit CTRL-D and the parent shell cleans up and exits as well. You could easily throw bash; into your ssh tunnel script just before the kill part so that when you log out of the nested shell your tunnel will be closed:

#!/bin/bash
ssh -nNT ... &
PID=$!
bash
kill $PID
查看更多
乱世女痞
5楼-- · 2019-01-20 21:57
  • You can tell ssh to go into background with & and not create a shell on the other side (just open the tunnel) with a command line flag (I see you already did this with -N).
  • Save the PID with PID=$!
  • Do your stuff
  • kill $PID

EDIT: Fixed $? to $! and added the &

查看更多
6楼-- · 2019-01-20 21:57

You could launch the ssh with a & a the end, to put it in the background and grab its id when doing. Then you just have to do a kill of that id when you're done.

查看更多
甜甜的少女心
7楼-- · 2019-01-20 21:58

Another potential option -- if you can install the expect package, you should be able to script the whole thing. Some good examples here: http://en.wikipedia.org/wiki/Expect

查看更多
登录 后发表回答