無需 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,以允許使用者在沒有完整 sudo 的情況下以 root 權限執行腳本。儘管如此,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

首先設定用於連接到「myhost」的自訂 SSH 金鑰。然後,編輯「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'

您也可以取代一個腳本來檢查其他一些條件來決定何時終止自身。這可能是處理這個問題的更乾淨的方法。

相關內容