mar*_*.47 5 linux ssh tunnel netstat ubuntu
我有一个 ssh 隧道侦听本地端口,比如 8888,从远程机器打开ssh -R 8888:localhost:80 myuser@myhost。我需要在“myhost”上为“myuser”编写一个脚本来关闭这个隧道。
该脚本将由“myuser”在“myhost”上执行。它不会由 root 执行,也不会执行 sudo。
一种方法是使用 lsof 或 netstat 找到侦听 8888 的进程的 PID,然后终止该进程。然而,lsof 和 netstat 都拒绝给我 PID 而不去 sudo。使用 netstat 我只是得到-而不是没有 sudo 的“PID/程序名称”。
有没有办法找出在没有根权限的情况下侦听给定端口的进程的 PID?侦听此端口的进程在我们所在的同一用户下运行。或者有没有其他方法可以从外部关闭 ssh 隧道?
请注意,使用 ssh 转义序列重置连接不是解决方案,因为我们不在隧道中。我们的脚本需要由同一用户在同一主机上单独运行。
另请注意,仅运行killall sshd不是解决方案,因为它会杀死所有其他 ssh 连接,而不仅仅是这个连接。
这个问题不是许多类似问题的重复,因为我发现他们接受的所有答案都需要 root 权限,或者只是杀死所有 ssh 连接。
主机“myhost”正在运行 Ubuntu 12.04.5。
编辑:@Jakuje 要求的讨论摘要:
@Patrick 建议了一种使用setuid或修改的方法,/etc/sudoers以允许用户在没有完整 sudo 的情况下以 root 权限运行脚本。虽然,因为setuid我们需要编写一个二进制文件而不是脚本。但是,允许用户以 root 权限运行脚本可能存在潜在的安全风险。而且这个解决方案仍然没有涵盖用户根本没有 root 访问权限的情况,所以他不能修改/etc/sudoers. 如果@Patrick 将此写为答案,我肯定会赞成它,但我不会将其标记为已接受。
@EricRenouf 发现 sshd 确实向用户显示了套接字,因此用户无法使用它/proc/*/fd来查找具有套接字的进程。这可能就是 lsof 和 netstat 都不显示的原因。
更多想法:
正如@EricRenouf 发现的那样,可能无法通过打开的套接字端口号或 inode 获取 sshd PID。但是我很好奇是否没有任何其他技巧可以找到这个 sshd PID 或如何告诉它关闭连接。也许以某种方式直接使用sshd。
例如,如果我启用了 sshd 调试模式,sshd -d那么它会记录哪个 sshd 进程打开了一个隧道,该隧道通向/var/log/auth.log用户可读的哪个端口。所以脚本可以解析日志并在那里找到 PID。但是运行调试模式 sshd 并不是一个好主意。实际上,即使没有调试模式,sshd也有一个简单的补丁可以记录打开的隧道。但我不确定运行打补丁的 sshd 是否也是一个好主意。
还有什么技巧吗?
首先设置用于连接到“myhost”的自定义 SSH 密钥。然后,编辑“myhost”上的 .ssh/authorized_keys 文件,以便将 shell 的父 PID 写入文件:
command="echo $PPID > tunnel.pid; bash" ssh-rsa AAA...
Run Code Online (Sandbox Code Playgroud)
您可能想要调整一些其他安全设置和/或者您可以编写一个自定义脚本来仅写入 PID 并挂起。无论哪种方式,原理都是相同的。
一旦您获得了保持 SSH 会话打开的进程的 PID,只需编写脚本即可...
kill `cat tunnel.pid`
Run Code Online (Sandbox Code Playgroud)
...终止进程,从而关闭 SSH 会话。
请注意,您可以使用-i命令的标志ssh来指定用于连接的私钥。
编辑:如果存在活动连接,终止 shell 进程不会关闭隧道,因此我们终止父 SSH 进程。
编辑:虽然我对任何自动 SSH 连接的第一个倾向是使用 SSH 密钥,但可以通过以下方式模拟相同的过程:
ssh -R 8888:localhost:80 myuser@myhost 'echo $PPID > tunnel.pid; for ((;;)); do sleep 1; done'
Run Code Online (Sandbox Code Playgroud)
您还可以替换一个脚本来检查其他一些条件来决定何时终止自身。这可能是处理这个问题的更干净的方法。