Git зависает без VPN? OpenSSH помечает пакеты через IPQoS
OpenSSH по умолчанию помечает свои пакеты значением QoS. Там, где маршрут отбрасывает эту метку, push зависает, пока туннель не изменит маршрут, по которому идут пакеты.
Клон из офиса работает, тот же клон через точку доступа телефона работает, а тот же клон из гостиничной сети висит, пока не включат VPN. Рукопожатие SSH завершается, и сеанс замолкает на первой настоящей передаче. Одна строка, добавленная в конфигурацию клиента, лечит git и ssh вместе. Когда одна настройка клиента исправляет несколько инструментов сразу, неисправность в том, что клиент отправляет, а не в канале, по которому он это отправляет.
Читайте симптом как разницу в маршрутизации
Туннель, который лечит проблему, редко бывает ремонтом. Он меняет маршрут, оператора и промежуточные устройства, а ноутбук продолжает создавать те же самые пакеты. Если один маршрут неправильно обрабатывает заголовок, а другой пропускает его без изменений, разница в политике промежуточного устройства, а не в клиенте. Здесь туннель — свидетель, а не решение.
Точка, в которой умирает сеанс, сужает поиск. Ничто из того, что срывается при поиске имени или при обмене ключами, так не выглядит. Сеанс, который проходит аутентификацию, печатает баннер и затем замирает на первой большой записи, уже доказал, что маршрутизация, имена и учётные данные работают.
Клиент ставит байт QoS на каждый сокет SSH
Каждое соединение OpenSSH начиная с 7.8 несёт в заголовке IP значение, которое маршрутизаторы могут использовать для приоритизации трафика. Терминальным сеансам достаётся одно значение, а массовым копиям другое, по теории, что человек, набирающий текст, заслуживает лучшего обращения, чем передача файла. Большинство сетей полностью игнорируют эту подсказку, поэтому она годами остаётся незамеченной. Меньшинство драйверов Wi-Fi, мобильных операторов и VPN-концентраторов реагирует на неё, и некоторые реагируют плохо.
Когда это значение переписывают или отбрасывают посреди потока, соединение не разрывается, оно перестаёт продвигаться. Повторы растут, окно рушится, а приложение ничего не сообщает, потому что ничего не вернуло ошибку. Именно это молчание заставляет людей описывать симптом как зависание, а не как сбой.
Сначала подтвердите версию клиента командой ssh -V. Любая версия начиная с 7.8 несёт такое поведение по умолчанию.
Три команды, которые отделяют это от MTU и DNS
Две похожие причины стоит исключить, прежде чем править любой файл конфигурации. Неисправность MTU пропускает мелкие обмены и замирает на первом крупном пакете, а неисправность имён вообще не создаёт сеанс.
ssh -o IPQoS=none -v [email protected]
ssh -G [email protected] | grep -i ipqos
sudo tcpdump -ni any -vv "tcp port 22"
Первая команда повторяет неудачную операцию с выключенной меткой, и её успешный запуск — самое сильное единичное доказательство, какое есть. Вторая печатает конфигурацию, которую клиент действительно применит к этому адресу, и это ловит устаревшую запись в файле, о котором вы забыли. Третья показывает байт TOS в обоих направлениях, пока передача стоит, и интересный узор — значение на сломанном маршруте и его отсутствие на рабочем.
Снимайте на ноутбуке, а не на сервере, потому что значение ставит отправитель и любое направление может его изменить. Сравните рабочий и неудачный маршруты одной и той же записью, и разница проявится без догадок.
Поместите исключение в один файл, по одному хосту за раз
Исключение должно стоять рядом с хостом, к которому относится, с комментарием, объясняющим, зачем оно существует.
Host gitlab.example.internal
IPQoS none
# direct route rewrites the marking; the tunnel route passes it
Область действия важнее самого значения. Запись с подстановочным знаком отключает поведение везде, выбрасывает подсказку, которая помогает в благополучных сетях, и не оставляет никому возможности сказать, когда она появилась. Запись для одного хоста читаема, обратима и легко удаляется после починки сети. Используйте пользовательский файл для личного обхода и управляемый файл, когда то же исключение нужно целому парку машин.
Чётко скажите, что исключение не покрывает. Оно относится к SSH, поэтому удалённый репозиторий HTTPS, зеркало пакетов и браузер остаются вне его, и сбой любого из них требует собственного доказательства. В цепочке через бастион каждый переход использует конфигурацию клиента, и застревающий переход — тот, который стоит ограничить.
Замкните круг с владельцем сети
Передайте находку как четыре факта: версия клиента, проверенный маршрут, используемый клиент VPN и какое направление несло метку. Этих четырёх достаточно владельцу сети, чтобы воспроизвести обращение и решить, намеренное ли оно.
Если исключение не лечит зависание, уберите его. Обход, переживший неудачный эксперимент, становится фольклором, и следующий человек тратит час, доказывая, что он ничего не делает. Если же он лечит зависание, путь всё ещё неверен для любого другого инструмента, который его пересекает, и ремонт — дело того, кто управляет промежуточным устройством.
Изменение на клиенте — это временное решение со сроком годности. Запишите этот срок в комментарий.