科技 · 實用指南
OpenSSH ControlMaster 卡住?刪除通訊端前先證明它已失效
解析實際 ControlPath,詢問主連線是否存活,區分陳舊路徑、遠端傳輸卡死與路徑故障,只修復已證實的邊界。

ControlMaster 故障並非單一問題:路徑可能解析到意外位置、超過 Unix 網域通訊端限制、位於無法正確承載通訊端的檔案系統、指向已退出的主程序,或仍連著本地主程序但遠端傳輸已卡死。先刪路徑會破壞證據,也可能與存活程序競爭。
依證據順序處理:用 ssh -G 固定有效設定,驗證私有 ControlPath 與長度,用 ssh -O check 詢問該精確通訊端,再依觀測結果選擇 exit、unlink、遷移路徑或保活修復;最後證明第二個用戶端確實重用了新主連線。
1. 固定別名與有效設定
使用故障時相同的別名與命令環境。執行 ssh -G alias,記錄 hostname、user、port、proxyjump、controlmaster、controlpath 與 controlpersist。OpenSSH 通常按命令列、使用者設定、系統設定取第一個值,只看最後的匹配區段可能找到錯誤通訊端。
不要手動展開另一個別名。%h、%p、%r、%C 等權杖來自有效連線;看似等價的名稱仍可能映射到不同主連線。保存完整輸出作為事故證據。
2. 在存活檢查前驗證路徑
確認解析後的 ControlPath 位於 SSH 使用者所有且他人不可寫的目錄。用 %h-%p-%r 保持唯一,長度緊張時用 %C。檢查父目錄搜尋權限與最終目錄寫入權限;缺失或不可寫的父目錄是路徑故障,不是陳舊通訊端。
量測編碼後的路徑名稱。Linux 的路徑通訊端 sun_path 為 108 位元組,其他實作可能更短,因此要保留餘量。短的私有執行階段目錄能避開過深的家目錄、容器或 CI 工作區。
3. 詢問精確主連線
以固定設定執行 ssh -O check alias。若必須直接測試捕獲路徑,使用 ssh -S "$socket" -O check host,並保持相同有效主機、使用者與連接埠。成功回應會識別執行中的主連線,通常回報 PID;變更前先保存輸出。
不要假設所有 OpenSSH 版本都有相同錯誤字串。沒有路徑時回查展開或建立;拒絕連線只是陳舊候選,仍要核對擁有者、檔案類型、別名與開啟通訊端的程序。檢查成功就轉查傳輸健康,不要刪除。
4. 區分陳舊路徑與傳輸卡死
若主連線回應且要停止它,執行 ssh -O exit alias,確認程序與路徑消失。不要刪除會回應的主連線路徑,否則舊用戶端可能繼續而新用戶端另建競爭主連線。只有無人回應、路徑屬於預期使用者且沒有匹配程序或開啟通訊端時,才保存證據並移除該已證實陳舊路徑。
控制通訊端回應只證明本地控制通道,不證明主連線仍能與伺服器交換資料。需要限制斷線時間時,同時設定 ServerAliveInterval 與 ServerAliveCountMax;它們透過加密協定訊息檢測遠端停止回應,與 TCPKeepAlive 不同。
5. 修復路徑與檔案系統位置
若通訊端在 overlay 或容器工作區建立失敗,在本地檔案系統的短私有執行階段目錄重現一次。有 CI 案例移出 overlayfs 後恢復,但只證明該位置邊界,不能推廣到所有 overlay。保留 %C 或其他按目標唯一的權杖。
優先使用使用者所有的 0700 目錄,例如合適的 $XDG_RUNTIME_DIR 子目錄。若受控測試使用 /dev/shm,必須建立私有子目錄並核對擁有者與模式;不可在共享可寫目錄直接放可預測通訊端。記錄 ControlPersist 與作業異常終止後的清理。
6. 證明修復並界定範圍
啟動一條詳細記錄連線並保存多工建立行;第二個程序用相同別名連線並確認重用,再執行 ssh -O check。比較修復前後 ssh -G,證明通過的是預期路徑與連線組合,而非退回非多工連線。
只有私有路徑可建立、精確主連線回應、第二用戶端重用、退出或持久化符合設計且遠端命令成功時才驗收。本流程涵蓋路徑式 ControlMaster 通訊端與抽樣用戶端;抽象通訊端、平台啟動器、安全模組、代理與供應商修補需額外證據。
