Действия по воспроизведению:

Действия по воспроизведению:

Почему OpenSSH_8.4p1 завершает другие сеансы, которые используют то же соединение, когда используется ProxyCommand? Есть ли способ предотвратить это?

Примечание: такое поведение, по-видимому, не происходит, если аргумент ProxyCommand опущен.

Действия по воспроизведению:

  1. Завершите все существующие общие подключения к localhost:
ssh -o ControlPath=/tmp/%C -O exit 127.0.0.1 2>/dev/null
ssh -o ControlPath=/tmp/%C -O exit localhost 2>/dev/null
  1. Выполните следующую команду дважды параллельно, каждую в отдельном терминале:
ssh -F none -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \
  -o ControlMaster=auto -o ControlPath=/tmp/%C -o ControlPersist=1d \
  -o ProxyCommand='ssh -W %h:%p 127.0.0.1' \
  localhost 'sleep 3600'
  1. Прервите первый процесс ssh с помощью SIGINT, набрав control-C.

Ожидаемое поведение

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

Фактическое поведение

  • Оба процесса завершены.

решение1

Завершается только процесс, обработанный SIGINT.

«Процесс» — ложная предпосылка. Ctrl+C отправляет SIGINTна передний план процессгруппатерминалаГруппа процессов может включать более одного процесса.

Тогда это актуально:

ProxyCommand
Указывает команду, используемую для подключения к серверу. Командная строка продолжается до конца строки и выполняется с использованием execдирективы оболочки пользователя, чтобы избежать затягивания процесса оболочки.
[…]

(источник)

Команда выполняется локально в той же группе процессов, что и main ssh. В вашем примере команда — , ssh …но в целом это может быть что угодно. В любом случае команда не знает об этом, ControlMasterи ControlPersistвы использовали для main ssh.

Когда вы нажимаете Ctrl+ C, каждый процесс в группе процессов переднего плана получает SIGINT. "Основной" процесс sshзавершается, не влияя на сокет в , ControlPathпоскольку в случае, ControlPersistотличном от noэтого, сокет с самого начала обрабатываетсяеще один sshпроцесс, который намеренно порождается в своей собственной группе процессов, это позволяет ему выживать. В этом контексте вы можете назвать его действительно основным ssh.

Неожиданное поведение связано с тем, что команда, указанная с , ProxyCommandпорождается в группе процессов переднего плана и не взаимодействует SIGINTс , которую sshвы хотите прервать. Команда реагирует на сигнал так, как если бы она это делала обычно. В вашем случае команда завершается на SIGINT. И поскольку команда должна была передавать все данные, главное соединение (действительно основное ssh) теперь бесполезно. Оно завершается вместе со всеми зависимыми sshпроцессами.

Таким образом, оригинал sshвыполняет дополнительную работу, чтобы гарантировать, sshчто обработка главного соединения (и сокета) выживет Ctrl+ C, но он не делает этого для команды, указанной с помощью, ProxyCommandкоторая не менее важна. Я думаю, вы можете назвать это ошибкой.

Вероятно, было бы лучше, если бы команда, указанная в, ProxyCommandбыла порождена иммунным sshвегоГруппа процессов. Я не проанализировал это достаточно тщательно. В любом случае, пока это не так, команда порождается в группе процессов, которая является группой процессов переднего плана в момент нажатия Ctrl+ C, поэтому она получает SIGINT.

Обходной путь — сделать команду невосприимчивой к SIGINT. Внутри ProxyCommandвы не можете использовать trapнапрямую, потому что ProxyCommanduses execавтоматически и exec trap …не имеет смысла и не будет работать. Вам нужна еще одна оболочка:

ssh -F none -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \
  -o ControlMaster=auto -o ControlPath=/tmp/%C -o ControlPersist=1d \
  -o ProxyCommand='sh -c "trap \"\" INT; exec ssh -W %h:%p 127.0.0.1"' \
  localhost 'sleep 3600'

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

Связанный контент