用于设置临时 SSH 隧道的 Bash 脚本

在 Cygwin 上,我想要一个 Bash 脚本:

  1. 创建到远程服务器的 SSH 隧道。
  2. 在使用隧道的地方做一些工作。
  3. 那就关闭隧道。

关闭的部分让我很困惑。

目前,我有一个蹩脚的解决方案:

# 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)

最后,当我完成后,我关闭第一个 shell 窗口来终止通道。

我想用一个脚本来完成这一切,比如:

# Create tunnel
# Do work
# Kill tunnel

我怎么跟踪隧道过程,才能知道该杀哪个?

76271 次浏览

您可以启动 ssh与一个结束的 &,把它放在后台,并获取其 id 时做。然后你只需要做一个 kill的 ID 当你完成。

  • 您可以告诉 ssh使用 &进入后台,而不要使用命令行标志在另一端创建 shell (只需打开通道)(我看到您已经使用 -N这样做了)。
  • PID=$!保存 PID
  • 做你该做的
  • kill $PID

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

我更喜欢为不同的任务启动一个新的 shell,我经常使用以下命令组合:

  $ sudo bash; exit

或者有时候:

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

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

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

您可以告诉 SSH 使用-f 选项进行背景设置,但是不能使用 $! 获得 PID。 此外,在使用隧道之前,脚本不需要任意睡眠时间,而是可以使用-o ExitOnForwardFalse = yes with-f,SSH 将等待所有远程端口转发成功建立,然后再将自身置于后台。您可以对 ps 的输出进行 grep 以获得 PID。例如,您可以使用

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

确保你得到了想要的 PID

您可以使用 ssh‘ control socket’干净利落地完成这项工作。与已经运行的 SSH 进程交谈并获取它的 pid、终止它等。使用“控制插座”(- M 表示 master,-S 表示 socket)如下:

$ ssh -M -S my-ctrl-socket -fNT -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 的回复得到这个信息。

Https://github.com/aronpc/remina-ssh-tunnel

#!/usr/bin/env sh


scriptname="$(basename $0)"
actionname="$1"
tunnelname=$(echo "$2" | iconv -t ascii//TRANSLIT | sed -E 's/[^a-zA-Z0-9-]+/-/g' | sed -E 's/^-+|-+$//g' | tr A-Z a-z)
remotedata="$3"
tunnelssh="$4"


if [ $# -lt 4 ]
then
echo "Usage: $scriptname start | stop LOCAL_PORT:RDP_IP:RDP_PORT SSH_NODE_IP"
exit
fi


case "$actionname" in


start)


echo "Starting tunnel to $tunnelssh"
ssh -M -S ~/.ssh/sockets/$tunnelname.control -fnNT -L $remotedata $tunnelssh
ssh -S ~/.ssh/sockets/$tunnelname.control -O check $tunnelssh
;;


stop)
echo "Stopping tunnel to $tunnelssh"
ssh -S ~/.ssh/sockets/$tunnelname.control -O exit $tunnelssh
;;


*)
echo "Did not understand your argument, please use start|stop"
;;


esac

用法例子

编辑或创建新的 Remmina 服务器连接

模式

~/.ssh/rdp-tunnel.sh ACTION TUNNELNAME LOCAL_PORT:REMOTE_SERVER:REMOTE_PORT TUNNEL_PROXY

姓名 描述
开拍 开始 | 停止
隧道名称 字符串识别套接字”缓慢地创建套接字文件到 ~/. ssh/sockets/string-Identity-socket. control
LOCAL _ PORT 如果我们使用同一个端口进行两个连接,那么将在本地暴露的门将会崩溃
远程服务器 如果在将要使用的代理服务器上拥有该服务器的 ip,则可以访问该服务器的 ip
(远程端口) 在服务器上运行的服务端口
隧道 _ 代理 你将要用作代理的连接,它需要在你的 ~/中。Ssh/config 最好使用访问键

我使用 Remmina 组名和连接名的组合 (% g -% p)作为我的 TUNNELNAME (这需要是唯一的,它将看到套接字名称)

预备指挥

~/.ssh/rdp-tunnel.sh start "%g-%p" 63394:192.168.8.176:3389 tunnel-name-1

指挥后

~/.ssh/rdp-tunnel.sh stop "%g-%p" 63394:192.168.8.176:3389 tunnel-name-1

image

你可以并且应该使用这个脚本来访问任何东西,我经常使用它来访问那些没有经过1、2、3、4、5个或更多 ssh 代理的公共 ip 的系统和服务

深入了解:

  1. Ssh 配置
  2. 嘘,马赫
  3. Ssh 跳跃主机
  4. 穿梭蟒

参考:

  1. Https://remmina.org/remmina-rdp-ssh-tunnel/
  2. Https://kgibran.wordpress.com/2019/03/13/remmina-rdp-ssh-tunnel-with-pre-and-post-scripts/
  3. 用于设置临时 SSH 隧道的 Bash 脚本
  4. Https://gist.github.com/oneohthree/f528c7ae1e701ad990e6

一个简单的 bash 脚本来解决您的问题。

# Download then put in $PATH
wget https://raw.githubusercontent.com/ijortengab/bash/master/commands/command-keep-alive.sh
mv command-keep-alive.sh -t /usr/local/bin


# open tunnel, put script in background
command-keep-alive.sh "ssh -fN -o ServerAliveInterval=10 -o ServerAliveCountMax=2 -L 33306:localhost:3306 myserver" /tmp/my.pid &
# do something
mysql --port 33306
# close tunnel
kill $(cat /tmp/my.pid)