Bash脚本设置临时SSH隧道


132

在Cygwin上,我希望Bash脚本能够:

  1. 创建到远程服务器的SSH隧道。
  2. 在本地使用隧道进行一些工作。
  3. 然后关闭隧道。

关闭部分让我感到困惑。

目前,我有一个me脚的解决方案。在一个shell中,我运行以下命令来创建隧道:

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

然后,在另一个Shell窗口中,我进行工作:

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

最后,完成后,我关闭第一个外壳窗口以杀死隧道。

我想在一个脚本中完成所有操作,例如:

# Create tunnel
# Do work
# Kill tunnel

如何跟踪隧道过程,以便知道要杀死哪个?


我写了一个脚本来帮助进行ssh隧道传输,您可以在以下网址
Nam Nguyen

Answers:


324

您可以使用ssh'控制套接字'干净地执行此操作。要与已经运行的SSH进程进行对话并获取它的pid,请杀死它,等等。使用“控制套接字”(-M为主服务器,-S为主套接字),如下所示:

$ 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. 

请注意,my-ctrl-socket将是创建的实际文件。

我从OpenSSH邮件列表上非常RTFM的答复中获得了此信息。


6
到目前为止,这是我在该主题上看到的最佳答案。非常感谢,它应该被接受。我用它来连接到我的Vagrant VM并运行FlywayDB更新脚本。
基督教徒

2
显然,控制套接字并非在任何地方都可以使用。例如,我进入Operation not permitteddrone.io连续集成环境:muxserver_listen: link mux listener ssh-ctrl-socket.wsASkszgSBlK7kqD => ssh-ctrl-socket: Operation not permitted
Mikko Ohtamaa 2015年

那么my-ctrl-socket运行该文件后会发生什么呢?当我ls -la在当前文件夹中执行操作时,我再也看不到该文件了。
sachinruk

2
如果在脚本中使用它,则需要等待几秒钟的控制套接字可用。我的解决方案:while [ ! -e $ctrl_socket ]; do sleep 0.1; done
亚当·沃尔纳

当我这样做时,我会得到open failed: administratively prohibited: open failed并且我不认为这会打开隧道
Andy Ray

21

您可以使用-f选项告诉SSH使其本身成为后台,但不会使用$!获得PID。另外,您可以使-o ExitOnForwardFailure = yes与-f配合使用,而不是让脚本在进入隧道之前先休眠任意时间,然后SSH将等待所有远程端口转发成功建立,然后再将其置于后台。您可以gps ps的输出来获取PID。例如,您可以使用

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

并确保您获得所需的PID


您可能没有意识到,但这是个天才。我正在寻找一种跟踪SSH隧道PID的方法,并且几乎最终使用了systemd服务脚本。不再:我可以使用隧道名称grep需要的SSH进程。这个想法以某种方式完全让我跳过了。非常感谢!
aexl

19
  • 您可以告诉ssh我们进入后台,&而不用命令行标记在另一侧创建壳(只需打开隧道)(我看您已经使用了-N)。
  • 将PID保存为 PID=$!
  • 做你的东西
  • kill $PID

编辑:固定$?到$!并添加了&


3
如果我的脚本在到达KILL之前死于某个地方,则必须小心处理。
jm。

2
@jm:trap 'kill $PID' 1 2 15将涵盖脚本失败的许多情况。
诺曼·拉姆西

3
为了使它可靠地工作,在创建隧道之后,我不得不“睡觉”一点,但要使用它。
jm。

@NormanRamsey我想你的意思是trap "kill $PID",因为bash只会在双引号字符串内插入变量
JuanCaicedo

1
@JuanCaicedo只有在PID稍后重新定义变量时,区别才重要。trap调用内置函数时(OP的方法)或捕获到信号时(您的方法),将对变量进行扩展。两种方法在这里产生相同的结果。
Witiko

4

我更喜欢为单独的任务启动新的Shell,并且我经常使用以下命令组合:

  $ sudo bash; exit

或有时:

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

这些命令创建一个嵌套的shell,我可以在其中完成所有工作。完成后,我按CTRL-D,父外壳也会清理并退出。您可以bash;在该kill部分之前轻松地放入ssh隧道脚本,这样当您退出嵌套外壳时,您的隧道将被关闭:

#!/bin/bash
ssh -nNT ... &
PID=$!
bash
kill $PID

很有意思。这样可以更好地处理“陷阱”问题。将不得不尝试。
jm。

2

您可以启动ssh带有a &末尾的,将其放在后台并在执行操作时获取其ID。完成后,您只需要做一个killid。


请注意是否使用与号(“&”)。这是一个丑陋的方法,因为您将必须确定为自己建立的实际连接。这可能会导致执行其他代码,而这些代码没有等待实际连接完全建立。此外,如果脚本中断,连接不会自动终止。
乔纳森

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.