防火墙后面的计算机(在远程位置)连接到我的服务器以打开隧道...目的是让我可以从服务器通过 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)
答案1
autossh
http://www.harding.motd.ca/autossh//http://packages.debian.org/squeeze/autossh可以监视现有连接的运行状况(通过绕过本地和远程端口转发循环传递流量)并重新连接失败/正在失败的连接(通过重新运行 ssh)。
netstat -tlp
将为您提供打开远程端口的进程 ID,这可能有助于追踪正在使用的新随机端口。
答案2
我有类似的模型,虽然没有端口随机化,但我运气很好。我让远程 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 文件包含以下内容(部分内容[省略]):
command="",no-user-rc,no-pty,no-X11-forwarding,no-agent-forwarding ssh-rsa AAA[more keys]RQ== rsa-hider-tunnel-key
在 Home 上,~/.ssh/config 具有以下内容。请注意 ServerAliveCountMax,允许在 Home 上的 SSH 否则会死亡之前丢失更多 keepalive 消息(默认值为 3)。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,这是一个好主意。
答案3
我目前使用的解决方案是将打开隧道的命令分为两部分:
while true; do
PORT=$(((RANDOM %= 1000) + 2000));
ssh "server" "record_port.sh '$PORT';";
ssh -N -R $PORT:localhost:22 -o ServerAliveInterval=30 "server";
sleep 5;
done
虽然并不完美,但这意味着第一个 ssh 连接可以在指定将尝试的端口号后返回,然后第二个 ssh 连接可以在没有远程 shell 的情况下建立隧道。
这使得服务器上的“record_port.sh”只是运行(没有 while/sleep):
echo "$PORT" > "/tmp/tunnel.port";