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

Ошибка переадресации удаленного порта SSH

Следовать за: Похоже, что быстрая серия отключений, совпадающая с несколькими месяцами работы каждого сервера, вероятно, случайна и служит лишь для выявления реальной проблемы. Причина, по которой ему не удалось повторно подключиться, почти наверняка связана со значениями AliveInterval (ответ касперда). Использование параметра ExitOnForwardFailure должно позволить истечение тайм-аута перед повторным подключением, что должно решить проблему в большинстве случаев. Предложение MadHatter (сценарий уничтожения), вероятно, лучший способ убедиться, что туннель может повторно подключиться, даже если все остальное не удается.

У меня есть сервер (A) за брандмауэром, который инициирует обратный туннель на нескольких портах к небольшому VPS DigitalOcean (B), поэтому я могу подключиться к A через IP-адрес B. Туннель стабильно работал около 3 месяцев, но внезапно вышел из строя четыре раза за последние 24 часа. То же самое произошло некоторое время назад с другим провайдером VPS - месяцы безупречной работы, а затем внезапно несколько быстрых сбоев.

У меня есть сценарий на машине A, который автоматически выполняет команду туннеля (ssh -R *:X:localhost:X address_of_B для каждого порта X), но когда он выполняется, он говорит Warning: remote port forwarding failed for listen port X.

Заходим в sshd /var/log/secure на сервере показывает такие ошибки:

bind: Address already in use
error: bind: Address already in use
error: channel_setup_fwd_listener: cannot listen to port: X

Решение требует перезагрузки VPS. До этого момента все попытки переподключения выдают сообщение «сбой переадресации удаленного порта» и работать не будут. Настало время, когда туннель длится всего около 4 часов до остановки.

На VPS ничего не изменилось, и это одноразовый однопользовательский компьютер, который служит только конечной точкой обратного туннеля. Он работает под управлением OpenSSH_5.3p1 на CentOS 6.5. Кажется, что sshd не закрывает порты на своем конце при потере соединения. Я не могу объяснить, почему или почему это внезапно случилось сейчас, после месяцев почти идеальной работы.

Чтобы уточнить, сначала мне нужно выяснить, почему sshd отказывается прослушивать порты после сбоя туннеля, что, похоже, вызвано тем, что sshd оставляет порты открытыми и никогда не закрывает их. Кажется, это основная проблема. Я просто не уверен, что могло бы заставить его вести себя таким образом после нескольких месяцев работы, как я ожидал (то есть сразу же закрывая порты и позволяя скрипту повторно подключиться).

Я согласен с MadHatter, что это скорее всего будет переадресация портов из несуществующих ssh-соединений. Даже если ваша текущая проблема окажется чем-то другим, вы можете ожидать, что рано или поздно столкнетесь с такими несуществующими ssh-соединениями.

Такие несуществующие соединения могут возникать тремя способами:

  • Одна из двух конечных точек была перезагружена, а другой конец соединения полностью простаивал.
  • Одна из двух конечных точек закрыла соединение, но в то время, когда соединение было закрыто, произошло временное отключение соединения. Отключение длилось несколько минут после закрытия соединения, поэтому другой конец так и не узнал о закрытом соединении.
  • Соединение по-прежнему полностью функционирует на обеих конечных точках ssh-соединения, но кто-то разместил где-то между ними устройство с отслеживанием состояния, которое прервало соединение из-за бездействия. Это устройство с отслеживанием состояния может быть либо NAT, либо брандмауэром, брандмауэр, о котором вы уже упоминали, является главным подозреваемым.

Выяснение того, что из трех вышеперечисленных происходит, не очень важно, потому что есть метод, который решит все три. Это использование сообщений keepalive.

Вы должны заглянуть в ClientAliveInterval ключевое слово для sshd_config и ServerAliveInterval интервал для ssh_config или ~/.ssh/config.

Запуск ssh команда в цикле может работать нормально. Хорошей идеей будет также включить в цикл засыпание, чтобы в конечном итоге вы не затопили сервер, когда соединение по какой-либо причине не удается.

Если клиент повторно подключается до того, как соединение на сервере было прервано, вы можете оказаться в ситуации, когда новое соединение ssh работает, но не имеет переадресации портов. Чтобы этого избежать, вам нужно использовать ExitOnForwardFailure ключевое слово на стороне клиента.

Для меня, когда ssh туннель отключается, требуется некоторое время для сброса подключения, поэтому ssh процесс продолжает блокироваться, оставляя меня без активных туннелей, и я не знаю почему. Обходное решение - поставить ssh в фон с -f и для создания новых подключений, не дожидаясь сброса старых подключений. В -o ExitOnForwardFailure=yes можно использовать для ограничения количества новых процессов. В -o ServerAliveInterval=60 повышает надежность вашего текущего соединения.

Вы можете повторить ssh часто, скажем, в cron, или в цикле вашего скрипта, например, в следующем примере, мы запускаем ssh команда каждые 3 минуты:

while (1)
do
    ssh -f user@hostname -Rport:host:hostport -N -o ExitOnForwardFailure=yes -o ServerAliveInterval=60
    sleep 180
done

Вы можете найти процесс, связывающий порт на этом сервере, с помощью

sudo netstat -apn|grep -w X

Похоже, что это наполовину несуществующий sshd, но зачем делать предположения, если у вас есть данные? Это также хороший способ для сценария найти PID для отправки сигнала 9, прежде чем пытаться снова запустить туннель.

По моему опыту, у ssh есть немного утомительная привычка не выходить чисто, если «что-то» все еще работает в удаленной системе. Например. началось в фоновом режиме. Вы можете воспроизвести это:

ssh <server>
while true; do  sleep 60; done&
exit

Ваш ssh выйдет из системы, но на самом деле не закроет сеанс - до тех пор, пока удаленный процесс не выйдет (чего не произойдет, потому что это цикл while true). Возможно, происходит что-то похожее - в вашем сеансе «застрял» процесс, порожденный ssh. Порт остается в использовании, и поэтому он не может быть повторно использован вашим локальным процессом.