我一直在瀏覽超級用戶的答案,但是我發現沒有任何答案可以解決我的用例。
我想連結我使用的兩個命令,讓我穿過隧道:
ssh -L 22:hostB:22 user@hostA
和
ssh -L 10002:localhost:10001 user@localhost
現在我要做的就是輸入第一個命令,打開另一個終端,然後輸入第二個命令。如果我做類似的事情
ssh … && ssh …
第二個命令僅在我從第一個連線「退出」後執行。
由於 hostA 上的伺服器配置,更高級的 ssh 選項(如 Jumphost)無法運作,因此我很確定這是可以像這樣存取 10001 連接埠的唯一選項。
有沒有一種方法可以將這兩個命令連結到一個別名中,或者使用一些帶有超時的簡單 bash 腳本等?
答案1
我認為你不能僅僅ssh -L 10002:hostB:10001 user@hostA
因為
- 監聽 B 的任何內容
10001
都只綁定到本地接口, - 或 B 上的防火牆不允許
hostB:10001
從 A 進行連接, - 管他呢。
ssh … && ssh …
第二個命令僅在我從第一個連線「退出」後執行。
是的,這是正常的。前面的部分&&
必須在下一個命令運行之前終止並返回退出狀態(或不終止,取決於狀態)。
這幾乎會立即運行第二個,ssh
但它有缺陷:
( ssh … & ) && ssh …
它是有缺陷的,因為第一個ssh
對第二個沒有影響。第二個可能會在第一個建立隧道之前運行。詢問密碼也可能會出現問題。
對於這個用例ssh
有-f
選項。從man 1 ssh
:
-f
請求ssh
在命令執行之前進入後台。 […]
所以基本指令可能是:
ssh -fNL 22:hostB:22 user@hostA && ssh -NL 10002:localhost:10001 user@localhost
-N
是否要與第二個一起使用取決於您ssh
。現在的技巧是ssh
在詢問密碼(如果適用)和建立第一個隧道後第一個分叉到後台,因此暫時有兩個「第一個」ssh
進程。後台的人開始處理隧道;前台的退出,這允許&&
工作。
你可能想要-o ExitOnForwardFailure=yes
。如果第一個隧道無法建立,第一個隧道ssh
將無法成功退出,第二個隧道也不會運作。改進後的命令為:
ssh -fNL 22:hostB:22 \
-o ExitOnForwardFailure=yes \
user@hostA &&
ssh -NL 10002:localhost:10001 user@localhost
請注意,當第二個ssh
退出時,第一個(在後台)仍然存在。好處是你可以ssh
稍後運行唯一的第二秒。缺點是如果您不想保留第一個,則需要手動殺死它。考慮到這一點,請考慮以下方法:
ssh -fNL 22:hostB:22 \
-o ExitOnForwardFailure=yes \
user@hostA
ssh -NL 10002:localhost:10001 user@localhost
注意沒有&&
.現在,如果舊的第一個ssh
仍在運行,那麼新的將失敗,因為它無法綁定到連接埠。無論如何,第二個隧道ssh
都會運行,它將使用第一個隧道,並且無論隧道有多舊。
可能會發生沒有舊的ssh
並且第一個ssh
由於某種原因而失敗的情況。如果是這樣,第二個將運行,但它可能會失敗(連接被拒絕),因為連接埠上沒有任何監聽22
。
您仍然可能不想離開「空閒」ssh
進程,您可能希望在第二次ssh
退出後自動終止它。顯然killall ssh
可能會造成附帶損害。讓我們找到更微妙的東西:
-M
將ssh
客戶端置於「主」模式以進行連線共享。 […][…]
-O ctl_cmd
控制活動連線復用主進程。 […][…]
-S ctl_path
指定用於連接共享的控制套接字的位置[...]
#!/bin/sh
socket=/tmp/hostA.socket
ssh -fNL 22:hostB:22 \
-o ExitOnForwardFailure=yes \
-MS "$socket"
user@hostA &&
{
ssh -NL 10002:localhost:10001 user@localhost
ssh -S "$socket" -O exit dummy
}
第二個ssh
終止後,第三個將告訴第一個退出。在第三個ssh
命令中,重要的是套接字,而不是主機名稱;您仍然需要提供一些主機名,因此dummy
.第一個ssh
將在退出之前刪除套接字,不應該留下任何垃圾。
仍然存在一些擔憂:
- 如果腳本被中斷,第一個腳本
ssh
將保留。要么在最開始就刪除&&
或發送,-O exit
以防萬一(這將是第零個ssh
)。 如果第一個
ssh
突然死亡,插座可能會保留。這將使任何新的第一次ssh
失敗。一個好主意可能是ssh
像這樣擴展第零個:ssh -S "$socket" -O exit dummy || rm "$socket"
/tmp/hostA.socket
可能不是插座的最佳位置。相當於命令列選項ssh_config
是.看什麼-S
ControlPath
man 5 ssh_config
對此說:建議
ControlPath
用於機會性連結共享的任何內容至少包括%h
、%p
、 和%r
(或%C
) 並放置在其他使用者不可寫入的目錄中。/run/user/$UID
如果您的作業系統支援的話,「其他使用者不可寫入的目錄」可能是(我相信這是systemd
事實)。