Новые подробности добавлены в конце этого вопроса; возможно, я пытаюсь понять причину.
У меня есть 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
показанная выше команда снова запускает соединение! Я не могу найти разумного объяснения того, почему это так, но я чувствую, что это может указывать на решение, которое в конечном итоге искоренит проблему.
Есть ли у кого-нибудь рекомендации, как еще попробовать?
Редактировать: Я вернулся и посмотрел на это немного дальше и нашел только более запутанную информацию:
Я установил соединение OpenVPN на фрагмент размером 1400 байт, как показано выше. Затем я подключился к VPN через Интернет и использовал Wireshark для просмотра пакетов UDP, которые были отправлены на сервер VPN во время остановки. Ни один из них не был больше указанного числа в 1400 байт, поэтому фрагментация, похоже, работает правильно.
Чтобы убедиться, что даже 1400-байтового MTU будет достаточно, я проверил связь с VPN-сервером, используя следующую команду (Linux):
ping <host> -s 1450 -M do
Это (я полагаю) отправляет 1450-байтовый пакет с отключенной фрагментацией (я, по крайней мере, подтвердил, что это не сработало, если я установил для него явно слишком большое значение, например 1600 байт). Кажется, они работают нормально; Я получаю ответы от хозяина без проблем.
Так что, возможно, это вообще не проблема 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 к клиентскому подключению