OpenVPN: Как смягчить проблемы с MTU пути на уровне отдельного клиента?

Вопрос или проблема

У нас установлено множество встраиваемых устройств у клиентов, все они подключаются к нашей службе OpenVPN. В общем, это работает нормально, но у некоторых клиентов есть серьёзные проблемы с MTU пути. Мы не можем повлиять на клиентов, чтобы они исправили свои сети, поэтому нам нужно, чтобы OpenVPN справлялся с этим. Вкратце, мой вопрос заключается в следующем:

Как я могу смягчить низкие MTU пути у некоторых клиентов на основе индивидуального подхода, без использования глобальных настроек, учитывающих крайние случаи для всех клиентов

Обратите внимание, что наш худший случай довольно плох: MTU пути 576 отбрасывает все фрагменты, сам не фрагментируется и не учитывает бит DF. Вы понимаете, почему я предпочёл бы не решать эту проблему глобально.

Страница мануала OpenVPN предлагает несколько вариантов, связанных с MTU, наиболее заметные из которых --link-mtu, --tun-mtu, --fragment и --mssfix. Но там также говорится

–link-mtu […] Лучше не устанавливать этот параметр, если вы не знаете, что делаете.

–tun-mtu […] Лучше использовать параметры –fragment и/или –mssfix для решения проблем с размером MTU.

Я начал экспериментировать с --fragment и --mssfix, но вскоре понял, что как минимум первый параметр должен устанавливаться не только на стороне клиента, но также на стороне сервера. Затем я рассмотрел конфигурацию на стороне сервера на основе --client-config-dir, но там сказано

Следующие параметры допустимы в контексте, специфичном для клиента: –push, –push-reset, –iroute, –ifconfig-push и –config.

Никаких упоминаний о параметрах MTU!

Итак, вот мои более конкретные вопросы:

  • Почему именно link-mtu и tun-mtu не рекомендуются? Какие потенциальные проблемы могут возникнуть с этими опциями? Обратите внимание, что я вполне уверенно разбираюсь в низкоуровневом редактировании заголовков IP.
  • Какие из опций link-mtu tun-mtu fragment mssfix должны быть зеркально установлены на стороне сервера, чтобы они работали?
  • Какие из опций link-mtu tun-mtu fragment mssfix можно использовать в client-config-dir?
  • Если все четыре опции необходимо зеркально устанавливать на стороне сервера и их нельзя использовать внутри client-config-dir, существуют ли альтернативы для борьбы с низким MTU пути для отдельных клиентов?

Заметки:

  • Некоторые из моих вопросов уже задавались 5 лет назад здесь, но они тогда не получили ответа, поэтому я осмеливаюсь их повторить.
  • Сервер OpenVPN в данный момент 2.2.1 на Ubuntu 12.04. Мы готовим обновление до 2.3.2 на Ubuntu 14.04
  • Клиенты OpenVPN — 2.2.1 на Debian 7.6
  • Я готов вручную определить MTU пути клиента
  • В данный момент мы не можем много тестировать на стороне сервера. Но мы строим совершенно отдельную тестовую среду, которая скоро будет готова.

Я решил проблему на стороне клиента, добавив опцию mssfix 1300 в файл конфигурации.

Из мануала OpenVPN:

--mssfix max
    Сообщает TCP-сессиям, работающим через туннель, чтобы они ограничили свои размеры отправляемых пакетов, чтобы после того, как OpenVPN их инкапсулирует, размер UDP-пакета, который OpenVPN отправляет своему пиру, не превышал max байт.

Изначальная идея моего решения пришла с personalvpn.org

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

Кратко: переходите к последнему вопросу/ответу для возможного решения


  • Почему именно link-mtu и tun-mtu не рекомендуются? Какие потенциальные проблемы могут возникнуть с этими опциями? Обратите внимание, что я вполне уверенно разбираюсь в низкоуровневом редактировании заголовков IP.

По моему опыту, как пользователя OpenVPN, в большинстве распространённых случаев это на самом деле fragment и/или mssfix, с которыми лучше не возиться, то есть в отличие от того, что говорит документация.

Значения link-mtu и tun-mtu вычисляются относительно друг друга в зависимости от того, какой шифр (если он используется) используется для туннеля. По умолчанию tun-mtu должно составлять классические 1500 байт, в то время как link-mtu выводится из этого, но вы можете установить любое из них, и, следовательно, другое будет пересчитано соответственно. В этом отношении существует довольно точное правило практики: никогда не устанавливайте оба: установите только одно, потому что другое просто будет следовать за ним.

Единственный случай, когда я сталкивался с проблемами при их изменении, это когда я установил конечные точки с очень разными значениями и с сервером, на котором было очень низкое значение, например 576, а у клиента 1500. Такие настройки просто не осуществляют обмен данными, и я никогда не углублялся в дальнейшее исследование, потому что, по правде говоря, у меня были такие настройки только в условиях искусственных лабораторных испытаний. Обратный случай, то есть низкое значение у клиента, в то время как на сервере нормальное/высокое значение, работает просто отлично.

На самом деле, я обнаружил, что установка link-mtu или tun-mtu (в основном я предпочитаю устанавливать link-mtu) фактически решает большинство распространённых проблем, то есть туннель работает так, как и должен, включая любой трафик, не относящийся к TCP.

Конечно, установка значений fragment и/или mssfix (если они также явно установлены) должны учитывать явные значения link-mtu/tun-mtu, но я发现, что просто оставлять их в покое (то есть даже не упоминать в конфигурации) обычно лучшее решение, потому что они просто корректируются автоматически в соответствии со значениями link-mtu/tun-mtu.

Тем не менее, верно, что установка только mssfix (оставляя link-mtu/tun-mtu и fragment неуказанными) решает всё, связанное с TCP, но все остальные протоколы, скорее всего, столкнутся с проблемами, единственной причиной, по которой они обычно не сталкиваются с проблемами, является то, что большинство трафика не относящегося к TCP либо DNS по UDP, что обычно имеет небольшой размер, либо ICMP эхо-запросы/ответы, которые, опять же, по умолчанию являются небольшими пакетами.

Обратите внимание, что я говорю о OpenVPN на Linux; на других операционных системах, особенно в линейке Windows и устройствах iOS, может быть другая картина, то есть изменение link-mtu/tun-mtu может быть неуместным или даже разрушительным, и вам может быть необходимо обращаться к изменению fragment/mssfix, как предлагается в документации. Особенно сложные случаи могут возникнуть, когда либо сервер, либо клиенты (или оба) не поддерживают фрагментацию/сборку IP, что может быть вызвано искусственным снижением link-mtu/tun-mtu, и в таких случаях вы можете только обращаться к включению fragment в OpenVPN.


  • Какие из опций link-mtu tun-mtu fragment mssfix должны быть зеркально установлены на стороне сервера для работы?

Согласно предупреждающим сообщениям, выдаваемым OpenVPN в его журнал, когда вы устанавливаете либо link-mtu, либо tun-mtu, не зеркаля их до конечной точки, значения link-mtu и tun-mtu должны быть точно зеркально установлены, либо явно, либо неявно. Однако на практике я никогда не сталкивался с проблемами при изменении любого из этих значений, даже когда я закончился с очень разными значениями между конечными точками туннеля.

fragment должен либо быть присутствовать с обеих сторон, либо отсутствовать с обеих сторон, потому что его присутствие активирует фрагментацию, выполняемую самим OpenVPN с использованием своего внутреннего алгоритма (не IP-фрагментации), и, таким образом, это должно быть согласовано обеими конечными точками. Однако, когда он присутствует, он может иметь асимметричные значения.

mssfix не нужно зеркалить, и оно также может иметь асимметричные значения между конечными точками.


  • Какие из опций link-mtu tun-mtu fragment mssfix можно использовать в client-config-dir?

Никакие


Возможное решение

  • Если все четыре опции необходимо зеркально устанавливать на стороне сервера и их нельзя использовать внутри client-config-dir: существуют ли альтернативы для борьбы с низким MTU пути для отдельных клиентов?

Одним из способов является использование параметров маршрутизации в Linux, которые позволяют устанавливать значения MTU произвольно, вплоть до MTU фактического интерфейса. Это делается следующим образом:

Для начала выполните ручное обнаружение MTU пути (например, используя команды ping -M do -s xxxx <public-address-пользователя> с сервера к удалённым клиентам), чтобы выяснить правильное значение MTU между сервером и каждым конкретным удалённым клиентом. Затем,

на стороне клиента, если это именно клиент, а не маршрутизатор для других хостов в его локальной сети, просто установите значение link-mtu OpenVPN на фактический MTU минус 28. Например, на удалённом клиенте с фактическим MTU 576 значение link-mtu 548 сработает.

Обратите внимание, что это будет действовать для всего трафика (не только TCP), исходящего от клиента, потому что значение link-mtu используется OpenVPN как верхний предел для его собственных (UDP порт 1194) нагрузок, отправляемых в удалённую конечную точку, следовательно, фактический MTU удалённого клиента (как было установлено вручную) минус 20 (размер внешнего заголовка IP без опций) минус 8 (размер внешнего заголовка UDP).

Значение MSS, которое OpenVPN будет автоматически ограничивать для TCP-трафика в туннеле, будет link-mtu минус собственные накладные расходы OpenVPN (которые варьируются в зависимости от используемого шифра), минус 20 (размер внутреннего заголовка IP без опций) минус 20 (размер внутреннего заголовка TCP без опций).

на стороне сервера, установите один маршрут для каждого “клиента с низким MTU”, чтобы установить правильный MTU для каждого из них. Каждое правильное значение, которое нужно установить в параметрах маршрута, должно быть тем, что вы установили для значения link-mtu этого удалённого клиента (как было установлено ранее) минус собственные накладные расходы OpenVPN. Последние можно вывести из значения link-mtu минус значение tun-mtu, отчет о котором делает сервер OpenVPN для этого конкретного туннеля. Например, предположим, что сервер OpenVPN сообщает о link-mtu 1541 и tun-mtu 1500, тогда на машине, на которой работает ваш сервер OpenVPN, вы сделаете что-то вроде:

ip route add <vpn-address-клиента> via <vpn-address-сервера> mtu 507

Такую операцию можно удобно выполнять по требованию с помощью скрипта client-connect, который получает эти значения (а также многие другие) в переменных окружения, устанавливаемых динамически OpenVPN. В терминах оболочки это будет:

ip route replace "$ifconfig_pool_remote_ip" via "$ifconfig_local" mtu "$(( 576 - 28 - (link_mtu - tun_mtu) ))"

С этого момента исходящий трафик в адрес конкретного клиента VPN будет соблюдать этот MTU, а не тот, который установлен для интерфейса туннеля.

Более того, если ваш сервер OpenVPN также выступает в качестве маршрутизатора (sysctl net.ipv4.ip_forward=1) между своей локальной сетью и удалёнными клиентами, тогда применяемые настройки по маршрутам на машине сервера OpenVPN (его ядре Linux) также инициируют корректные ICMP-сообщения (тип 3 код 4, требуется фрагментация) на машины в локальной сети, когда они отправляют трафик DF к удалённым клиентам, в этом случае эти другие машины в локальной сети должны соблюдать эти ICMP-сообщения, и они также произведут IP-фрагментацию внутри туннеля от имени машин в локальной сети, когда они отправляют трафик, не относящийся к DF, в этом случае ваши удалённые клиенты должны поддерживать сборку IP для IP-фрагментов, вышедших из туннеля.

Имейте в виду, что на Ubuntu 14.04 HWE и более поздних версиях (или эквивалентных ядрах до v5.7.x) вам также необходимо установить sysctl net.ipv4.ip_forward_use_pmtu=1, чтобы Linux выполнял указанные ICMP/фрагментацию при маршрутизации трафика других машин, в то время как эта дополнительная sysctl не требуется для исходящего трафика сгенерированного самой машиной сервера.

В заключение, отметьте, что для полностью корректной конфигурации вам также следует установить link-mtu 1472 (при предположении, что MTU нижнего интерфейса составляет 1500) на стороне сервера. Я действительно делаю это всякий раз, в любом месте, как базовую конфигурацию, за исключением специфических случаев, требующих определённых обходных путей. Это потому, что OpenVPN не считает MTU нижнего интерфейса стартовым значением для его link-mtu/tun-mtu, и он также не выполняет PMTU-обнаружение, даже когда его опция mtu-disc установлена в yes на ОС, которые это поддерживают. Поэтому, явная установка link-mtu на значение, отражающее MTU нижнего интерфейса (с использованием формул, которые я описал выше), на мой взгляд, является действительно оптимальным серёзным значением по умолчанию по крайней мере на Linux.

Надеюсь, это будет полезно

Учитывая отсутствие ответов, я сейчас публикую решение, которое не очень элегантно, но просто: запустите другой экземпляр OpenVPN на TCP для “плохих клиентов”

proto tcp

и уменьшите TCP MSS на стороне клиента, например,

iptables -t mangle -A POSTROUTING -p tcp --tcp-flags SYN,RST SYN -o ${OUT_DEV} -j TCPMSS --set-mss ${PATH-MTU-MINUS-40}

Преимущество этого решения в том, что каждый клиент может установить свой индивидуальный MSS.

Это, бесспорно, TCP-над-TCP, но, как должно работать неплохо в многих сценариях.

Обратите внимание, что я всё ещё очень заинтересован в решениях, которые не требуют proto tcp, и я отмечу их как действительный ответ, если они более или менее удовлетворяют мои изложенные требования.

Ответ или решение

Чтобы смягчить проблемы с MTU (Maximum Transmission Unit) на стороне клиентов OpenVPN, необходимо рассмотреть несколько эффективных методов и принятия решений. Тем не менее, эти методы должны быть настраиваемыми индивидуально для каждого клиента, чтобы избежать влияния на всю сеть. Давайте разберем ваши вопросы по порядку.

Проблемы с link-mtu и tun-mtu:

  • Эти параметры могут вызвать проблемы, если их устанавливают на обоих концах туннеля (сервер и клиент) с разными значениями. Например, если у сервера установлен низкий MTU, а у клиента — высокий, туннель может не устанавливаться вовсе.
  • link-mtu и tun-mtu определяют максимальный размер пакетов, которые отправляются по туннелю. Установив их неправильно, вы можете столкнуться с тем, что данные будут отбрасываться, что повысит вероятность потерь пакетов и падения производительности.

Рекомендуется использовать mssfix и fragment, которые более гибкие и меньше подвержены проблемам при изменении MTU.

2. Какие опции нужно дублировать на серверной стороне?

  • fragment: Должен быть установлен на обеих сторонах. Это позволяет OpenVPN фрагментировать пакеты по своему собственному алгоритму.
  • mssfix: Не требует дублирования. Может иметь различные значения на клиенте и сервере.
  • link-mtu и tun-mtu: Рекомендуется устанавливать одинаковые значения на обеих сторонах туннеля, иначе могут возникнуть проблемы с установлением туннеля.

3. Какие опции можно использовать в client-config-dir?

К сожалению, в контексте client-config-dir нельзя использовать link-mtu, tun-mtu, fragment и mssfix. Эти параметры необходимо устанавливать в глобальных конфигурациях на сервере.

4. Альтернативы для борьбы с низким MTU на уровне клиента

Если указанные параметры должны быть установлены на сервере и не могут быть настроены для клиентов через client-config-dir, рассмотрите следующие подходы:

  • Проведение ручного тестирования PMTU: Используйте команды типа ping -M do -s [размер] [адрес] для проверки MTU клиента. Установите значение mssfix в зависимости от полученных данных, например, mssfix 1300.

  • Использование маршрутизации на уровне Linux: Установите MTU на специфичном маршруте для каждого клиента на серверной стороне:

    ip route add [адрес клиента] mtu [значение]

    Это можно автоматизировать с помощью скрипта подключения.

Итоговое решение

В случае, если ни один из вышеперечисленных методов не подходит, вы можете рассмотреть возможность запуска отдельного экземпляра OpenVPN на TCP специально для клиентов с проблемами MTU. Этот подход позволит установить свои настройки MSS индивидуально для каждого клиента.

Пример настройки TCP:

proto tcp

Кроме того, используйте iptables для снижения MSS, если это необходимо:

iptables -t mangle -A POSTROUTING -p tcp --tcp-flags SYN,RST SYN -o ${OUT_DEV} -j TCPMSS --set-mss ${PATH-MTU-MINUS-40}

Ваша конфигурация может влиять на производительность, поэтому тестируйте каждое решение в лабораторных условиях перед внедрением в продуктивную среду.

Оцените материал
Добавить комментарий

Капча загружается...