Networking

保持 SSH 隧道打開,並執行遠端命令

  • April 19, 2012

防火牆後面的電腦(位於遠端位置)連接到我的伺服器以打開隧道……目的是我可以從伺服器通過 SSH 連接到電腦。

電腦與以下設備建立連接:

while true; do
   PORT=$(((RANDOM %= 1000) + 2000));
   ssh -R $PORT:localhost:22 -o ServerAliveInterval=30 "server" "record_port.sh '$PORT';";
   sleep 5;
done

伺服器上的“record_port.sh”shell 腳本包含:

echo "$PORT" > "/tmp/tunnel.port";
while true; do
   sleep 300;
done

然後我可以連接到伺服器:

function computer {
 ssh -p `cat /tmp/tunnel.port` -o NoHostAuthenticationForLocalhost=yes localhost
}

伺服器在 /etc/ssh/sshd_config… 中還有一個“ClientAliveInterval 30”,並使用 rbash 和 dss 鍵之類的東西。

我使用隨機埠,因為我發現有時該埠已被使用,目的是如果我終止伺服器上的連接,電腦將在 5 秒後使用新埠重新連接。

而且因為它是一個隨機埠,所以我需要 shell 腳本來記錄正在使用的埠(lsof 沒有任何運氣)。

但問題是,如果網際網路連接失去並且隧道關閉,電腦會很高興地在不同的埠號上重新連接新隧道,但原始程序(record_port.sh)仍在繼續:

ps ax | grep "report_port"
4166 ? Ss 0:00 /bin/bash /home/tunnel/bin/report_port.sh 2833
6863 ? Ss 0:00 /bin/bash /home/tunnel/bin/report_port.sh 2605
20109 ? Ss 0:00 /bin/bash /home/tunnel/bin/report_port.sh 2023

pstree
init(1)─┬─...
       ├─sshd(28187)─┬─sshd(6860)───sshd(6862)───tunnel.port.sh(6863)───sleep(15533)
       │             ├─sshd... (my current shell)
       ├─tunnel.port.sh(4166)───sleep(15232)
       ├─tunnel.port.sh(20109)───sleep(15318)

autossh http://www.harding.motd.ca/autossh/ / http://packages.debian.org/squeeze/autossh可以監控現有連接的健康狀況(通過在本地和遠端埠轉發循環周圍傳遞流量)並重新連接失敗/失敗的(通過重新執行 ssh)。

netstat -tlp將為您提供打開遠端埠的程序 ID,這可能有助於跟踪正在使用的新隨機埠。

儘管沒有埠隨機化,但我對類似的模型非常幸運。我在遠端 NAT 後面將我稱為“Hider”的電腦直接連接到具有公共 IP 的本地中央伺服器,我將稱為“Home”。此 SSH 連結的目的是在 Home 端創建用於訪問 Hider 上的 SSH 的埠。

這是在 Hider 上執行的腳本:

#/bin/sh
#  script: allow-ssh-from-home
unset DISPLAY
interval=30
while : ; do
   echo opening tunnel at `date +'%Y-%m-%d %H:%M:%S %Z'`
   if ssh -NC \
       -o IdentitiesOnly=yes \
       -o IdentityFile=$HOME/.ssh/id_rsa-hider-tunnel \
       -o CheckHostIP=no \
       -o StrictHostKeyChecking=no \
       -o UserKnownHostsFile=/dev/null \
       -o GSSAPIAuthentication=no \
       -o PasswordAuthentication=no \
       -o ServerAliveInterval=30 \
       -o ExitOnForwardFailure=yes \
       -R2222:127.0.0.1:22 \
       home.example.com
   then
       echo Respawning after success...
   else
       echo Delaying $interval seconds after failure... | tr -d '\012'
       sleep $interval
       echo done.  Respawning...
   fi
done
#------------------------------------eof

在 Hider 上,~/.ssh/authorized_keys 文件有這個(有一些

$$ elided $$):

command="",no-user-rc,no-pty,no-X11-forwarding,no-agent-forwarding ssh-rsa AAA[more keys]RQ== rsa-hider-tunnel-key

在首頁上, ~/.ssh/config 具有以下內容。注意 ServerAliveCountMax,允許更多的 keepalive 消息被遺漏(預設為 3),否則 Home 上的 SSH 會死掉。Hider 上也可能存在相同的配置,儘管我不確定,因為已經有一段時間了。

Host localhost
    NoHostAuthenticationForLocalhost yes

Host *
   HashKnownHosts no
   FallBackToRsh no
   ForwardAgent yes
   ForwardX11 yes
   Compression yes
   ServerAliveInterval 30
   ServerAliveCountMax 120

Hider上的使用模式是登錄,然後:

$ exec ssh-agent bash
$ ssh-add         # add a key known for yourself@Home
$ exec allow-ssh-from-home   # links to Home, logs out if interrupted

現在,從任何地方登錄到首頁,然後:

ssh -p 2222 localhost

此時,Hider 將需要身份驗證——這是一個好主意,以防有人闖入 Home。

引用自:https://serverfault.com/questions/380598