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

Как предотвратить зависание TCP-соединения в сети OpenVPN?

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

У меня есть VPN на основе UDP OpenVPN, настроенная в tap режим (мне нужен tap потому что мне нужен VPN для передачи многоадресных пакетов, что, похоже, невозможно с tun сетей) с несколькими клиентами через Интернет. Я часто сталкивался с зависаниями TCP-соединения через VPN. То есть я установлю TCP-соединение (например, SSH-соединение, но у других протоколов есть аналогичные проблемы), и в какой-то момент во время сеанса кажется, что трафик перестанет передаваться через этот сеанс TCP.

Похоже, это связано с точками, в которых происходят большие передачи данных, например, если я выполняю ls в сеансе SSH, или если я cat длинный файл журнала. Некоторые поисковые запросы в Google дают несколько ответов как этот предыдущий о сбое сервера, указывая на то, что вероятной причиной является проблема с MTU: что в периоды высокого трафика VPN пытается отправить пакеты, которые отбрасываются где-то в каналах между конечными точками VPN. В приведенном выше ответе предлагается использовать следующие параметры конфигурации OpenVPN для смягчения проблемы:

fragment 1400
mssfix

Это должно ограничить MTU, используемое в VPN, до 1400 байтов и зафиксировать максимальный размер сегмента TCP, чтобы предотвратить создание любых пакетов большего размера. Кажется, это немного смягчает проблему, но я все еще часто вижу зависание. Я пробовал несколько размеров в качестве аргументов fragment директива: 1200, 1000, 576, все с аналогичными результатами. Я не могу представить себе какую-либо странную топологию сети между двумя концами, которая могла бы вызвать такую ​​проблему: VPN-сервер работает на pfSense машина подключена напрямую к Интернету, и мой клиент также напрямую подключен к Интернету в другом месте.

Еще один странный кусок головоломки: если я запустил tracepath утилита, то это, похоже, решает проблему. Пример выполнения выглядит так:

[~]$ tracepath -n 192.168.100.91
 1:  192.168.100.90                                        0.039ms pmtu 1500
 1:  192.168.100.91                                       40.823ms reached
 1:  192.168.100.91                                       19.846ms reached
     Resume: pmtu 1500 hops 1 back 64 

Вышеупомянутый запуск выполняется между двумя клиентами в VPN: я инициировал трассировку с 192.168.100.90 к месту назначения 192.168.100.91. Оба клиента были настроены с fragment 1200; mssfix; в попытке ограничить MTU, используемый для ссылки. Приведенные выше результаты, казалось бы, предполагают, что tracepath смог определить MTU пути в 1500 байт между двумя клиентами. Я бы предположил, что он будет несколько меньше из-за настроек фрагментации, указанных в конфигурации OpenVPN. Я нашел этот результат несколько странным.

Однако еще более странно: если у меня TCP-соединение в остановленном состоянии (например, сеанс SSH с зависшим в середине списком каталогов), то выполнение tracepath показанная выше команда снова запускает соединение! Я не могу найти разумного объяснения того, почему это так, но я чувствую, что это может указывать на решение, которое в конечном итоге искоренит проблему.

Есть ли у кого-нибудь рекомендации, как еще попробовать?

Редактировать: Я вернулся и посмотрел на это немного дальше и нашел только более запутанную информацию:

Так что, возможно, это вообще не проблема MTU. Я просто не понимаю, что это еще может быть!

Изменить 2: Кроличья нора становится все глубже: теперь я немного выделил проблему. Похоже, это связано с конкретной ОС, которую использует клиент VPN. Я успешно воспроизвел проблему как минимум на трех машинах Ubuntu (версии с 12.04 по 13.04). Я могу надежно продублировать зависание SSH-соединения в течение минуты или около того, просто cat-ing большой файл журнала.

тем не мение, если я провожу тот же тест, используя машину CentOS 6 в качестве клиента, то я не вижу проблемы! Я тестировал ту же версию клиента OpenVPN, что и на машинах Ubuntu. Я могу cat log файлы часами, не видя зависания соединения. Кажется, это дает некоторое представление об основной причине, но я просто не уверен, что это за понимание.

Я изучил трафик через VPN с помощью Wireshark. Я не эксперт по TCP, поэтому я не уверен, что делать с кровавыми деталями, но суть в том, что в какой-то момент UDP-пакет теряется из-за ограниченной пропускной способности интернет-канала, что вызывает повторные передачи TCP внутри VPN-туннель. На клиенте CentOS эти повторные передачи происходят правильно, и все идет благополучно. Однако в какой-то момент с клиентами Ubuntu удаленный конец начинает повторно передавать один и тот же сегмент TCP снова и снова (с увеличением задержки передачи между каждой повторной передачей). Клиент отправляет то, что выглядит как действительный TCP ACK при каждой повторной передаче, но удаленный конец по-прежнему продолжает периодически передавать один и тот же сегмент TCP. Это продолжается до бесконечности, и соединение останавливается. Мой вопрос здесь будет:

Одним из общих различий между узлом CentOS и различными выпусками Ubuntu является то, что Ubuntu имеет гораздо более новую версию ядра Linux (с 3.2 в Ubuntu 12.04 до 3.8 в 13.04). Может быть, указатель на какую-то новую ошибку ядра? Я предполагаю, что если бы это было так, то я был бы не единственным, у кого возникла проблема; Не думаю, что это выглядит особенно экзотично.

Эта команда решает это за меня:

$ sudo ip link set dev tun0 mtu 1350 && echo ":)"

Вы можете проверить настройки tun0 с помощью

$ ip a s

Ура!

Отключить масштабирование окна в TCP с помощью:

sysctl -w net.ipv4.tcp_window_scaling=0

После этого SSH для Debian / Ubuntu Systems через VPN у меня работает нормально.

В Windows с использованием Putty вам нужно изменить MTU, перейдя к локальному подключению для подключения vpn -> сведения о сетевом интерфейсе (адаптер TAP Windows или что-то в этом роде) -> Advanced -> Properties -> MTU (измените его на что-то ниже 1500). Возможно, вам придется переподключиться. У меня сработало на Windows и Putty

Похоже, это проблема с буферизацией. У меня такая же проблема, и я могу избежать ее, уменьшив скорость передачи. Не лучший способ, но может помочь кому-то найти лучшее решение для этого.

Смотрите обновление 1 здесь: Как предотвратить зависание SSH при подключении клиента openvpn к клиентскому подключению