无需 root 身份即可关闭 ssh 隧道,且无需终止所有其他 ssh 连接

无需 root 身份即可关闭 ssh 隧道,且无需终止所有其他 ssh 连接

我有一个 ssh 隧道,它监听本地端口 8888,它是用 从一个远程机器打开的ssh -R 8888:localhost:80 myuser@myhost。我需要为“myhost”上的“myuser”编写一个脚本来关闭这个隧道。

该脚本将由“myhost”上的“myuser”执行。它不会由 root 执行,也无法使用 sudo。

一种方法是使用 lsof 或 netstat 找到监听 8888 的进程的 PID,然后终止该进程。但是,lsof 和 netstat 都拒绝在不使用 sudo 的情况下提供 PID。使用 netstat 时,我只得到-“PID/程序名称”,而无需 sudo。

有没有办法在没有 root 权限的情况下找出监听给定端口的进程的 PID?监听此端口的进程与我们相同的用户下运行。或者有没有其他方法可以从外部关闭 ssh 隧道?

请注意,使用 ssh 转义序列重置连接并不是解决方案,因为我们不是在隧道中。我们的脚本需要由同一用户在同一主机上独立于隧道运行。

还请注意,仅运行killall sshd并不是解决方案,因为它将终止所有其他 ssh 连接,而不仅仅是这个连接。

这个问题与许多类似的问题并不重复,因为我发现所有被接受的答案都需要 root 权限,或者只是终止所有 ssh 连接。

主机“myhost”正在运行 Ubuntu 12.04.5。


编辑:根据@Jakuje 的要求进行讨论总结:

  • @Patrick 建议使用setuid或修改的方法/etc/sudoers,以允许用户以 root 权限运行脚本,而无需完全 sudo。尽管如此,setuid我们需要编写一个二进制文件而不是脚本。但是,允许用户以 root 权限运行脚本可能存在潜在的安全风险。而且,此解决方案仍不涵盖用户根本没有 root 访问权限的情况,因此他无法修改/etc/sudoers。如果 @Patrick 将此作为答案,我肯定会赞成,但我不会将其标记为已接受。

  • @EricRenouf 发现 sshd 确实将套接字 chown 给用户,因此用户无法使用它/proc/*/fd来查找具有套接字的进程。 这可能是 lsof 和 netstat 都不显示它的原因。

更多想法:

正如@EricRenouf 发现的那样,可能无法通过打开的套接字端口号或 inode 获取 sshd PID。但我很好奇是否没有其他技巧可以找到此 sshd PID 或如何告诉它关闭连接。也许可以直接使用 sshd。

例如,如果我启用了 sshd 调试模式,sshd -d那么它将记录哪个 sshd 进程打开了隧道,哪个端口/var/log/auth.log可供用户读取。因此脚本可以解析日志并在那里找到 PID。但运行调试模式 sshd 并不是一个好主意。实际上有一个sshd 的简单补丁即使没有调试模式也可以记录打开的隧道。但我不确定运行修补的 sshd 是否是个好主意。

还有其他诀窍吗?

答案1

首先设置一个自定义 SSH 密钥以连接到“myhost”。然后,编辑“myhost”上的 .ssh/authorized_keys 文件,以便将 shell 的父 PID 写入文件:

command="echo $PPID > tunnel.pid; bash" ssh-rsa AAA...

您可能需要调整其他一些设置以确保安全,或者您可以编写自定义脚本来仅写入 PID 并挂起。无论哪种方式,原理都是一样的。

一旦您获得了保持 SSH 会话打开的进程的 PID,这只是一个脚本的问题......

kill `cat tunnel.pid`

...终止该进程,从而关闭 SSH 会话。

请注意,您可以使用-i命令的标志ssh来指定用于连接的私钥。

编辑:如果存在活动连接,终止 shell 进程不会关闭隧道,因此我们终止父 SSH 进程。

编辑:虽然我对任何自动 SSH 连接的第一倾向是使用 SSH 密钥,但可以使用以下命令模拟相同的过程:

ssh -R 8888:localhost:80 myuser@myhost 'echo $PPID > tunnel.pid; for ((;;)); do sleep 1; done'

您还可以替换一个脚本,该脚本会检查其他一些条件来决定何时终止自身。这可能是处理此问题的一种更简洁的方法。

相关内容