Назад | Перейти на главную страницу

Открытие туннеля SSH и выполнение удаленной команды

Компьютер за брандмауэром (в удаленном месте) подключается к моему серверу, чтобы открыть туннель ... намерение состоит в том, чтобы с сервера я мог подключиться к компьютеру через 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" на сервере содержит:

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

Затем я могу подключиться к серверу с помощью:

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

Сервер также имеет «ClientAliveInterval 30» в / etc / ssh / sshd_config ... и использует такие вещи, как ключи rbash и dss.

Я использую случайный порт, так как обнаружил, что иногда порт уже используется, с намерением, что если я убью соединение на сервере, компьютер через 5 секунд повторно подключится с новым портом.

И поскольку это случайный порт, мне нужен сценарий оболочки для записи используемого порта (мне не повезло с 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)

Мне очень повезло с подобной моделью, хотя и без рандомизации портов. У меня был компьютер, который я назову «Hider», за удаленным NAT, подключенным напрямую к локальному центральному серверу, который я назову «Home» с общедоступным IP. Целью этой ссылки SSH было создание порта на стороне Home, используемого для доступа к SSH на Hider.

Вот сценарий, запущенный на 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

На главной странице ~ / .ssh / config имеет следующее. Обратите внимание на ServerAliveCountMax, позволяющий пропустить больше сообщений keepalive (по умолчанию 3) до того, как в противном случае отключится SSH на Home. Та же самая конфигурация, вероятно, присутствовала и на 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.

autossh http://www.harding.motd.ca/autossh/ / http://packages.debian.org/squeeze/autossh может отслеживать состояние существующих подключений (передавая трафик по петле переадресации локальных и удаленных портов) и повторно подключать сбойные / сбойные (путем повторного запуска ssh).

netstat -tlp предоставит вам идентификатор процесса, открывающий удаленный порт, который может помочь в отслеживании нового используемого случайного порта.

Решение, которое я использую сейчас, - разделить команду открытия туннеля на две части:

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 может установить туннель без удаленной оболочки.

Это оставляет "record_port.sh" на сервере просто запущенным (без while / sleep):

echo "$PORT" > "/tmp/tunnel.port";