WireGuard MTU и PMTUD: диагностика зависающих соединений через VPN | AdminWiki

WireGuard MTU и PMTUD: диагностика зависающих соединений через VPN

20 сентября 2026 12 мин. чтения

Почему WireGuard-соединение зависает: роль MTU и PMTUD

Туннель WireGuard поднят, handshake проходит, ping отвечает, но SSH-сессия замирает при выводе большого файла, а HTTPS-страницы не догружаются. В большинстве случаев виновато не шифрование, а несоответствие MTU и сломанный Path MTU Discovery (PMTUD). WireGuard инкапсулирует исходный IP-пакет в UDP-датаграмму и добавляет собственные заголовки, поэтому полезная нагрузка внутри туннеля всегда меньше, чем на физическом интерфейсе. Когда пакет превышает MTU на каком-то участке пути и узел не может вернуть ICMP-уведомление об этом, соединение попадает в black hole: малые пакеты проходят, крупные тихо теряются.

Прямой ответ: универсального «правильного» MTU для WireGuard не существует. Значения 1420 или 1440, которые часто приводят как готовое решение, годятся только для одной конкретной комбинации транспорта и каналов. На расчёт влияют MTU физического интерфейса, PPPoE, VLAN, GRE, двойной NAT и версия IP. Рабочий путь такой: посчитать базовый overhead, выставить стартовое значение, затем проверить его ping с флагом DF и уменьшить, если крупные пакеты не проходят.

Второй фактор — PMTUD. Он позволяет узлу динамически узнать минимальный MTU на всём пути, но работает только при свободно ходящих ICMP. Многие администраторы блокируют ICMP целиком «для безопасности», и это ломает механизм. WireGuard сам PMTUD не выполняет: он инкапсулирует то, что ему отдал IP-стек. Значит, либо ICMP нужно пропустить, либо ограничить размер TCP-сегментов через MSS clamping. Отдельно учитывайте, что сервисы на WireGuard и OpenVPN активно распознаются и ограничиваются провайдерами, поэтому к транспортным сбоям нередко добавляются искусственные потери (описание ограничений VPN-трафика).

Симптомы black hole: когда ping работает, а SSH — нет

Классический сценарий black hole выглядит так. Команда ping на небольшом размере отвечает стабильно, потому что ICMP-echo по умолчанию несёт 56 байт данных. Но стоит открыть SSH и выполнить команду с большим выводом, например прочитать лог, и сессия зависает. TCP-сегмент с данными превышает MTU на промежуточном узле, а DF-бит запрещает фрагментацию. Узел отбрасывает пакет и должен вернуть ICMP Fragmentation Needed, но не делает этого: сообщение блокирует фаервол или фильтр. Отправитель повторяет попытку и снова получает те же потери.

Признаки, по которым black hole отличается от обычного сетевого сбоя:

  • ping на малых размерах проходит, при увеличении размера пакетов потери начинаются резко и держатся.
  • TCP-соединение устанавливается (SYN и SYN-ACK малы), но зависает при передаче данных.
  • scp, rsync и HTTP-загрузки останавливаются в произвольный момент, а мессенджеры и DNS работают.
  • Проблема проявляется периодически, когда балансировка по нескольким маршрутам отправляет крупные пакеты через узел с меньшим MTU.

Для IPv6 поведение то же, только уведомление называется ICMPv6 Packet Too Big. Строить проверку удобно по общему алгоритму поиска потерь и задержек из материала про диагностику сетевой производительности.

Накладные расходы туннеля WireGuard: сколько байт «съедает» инкапсуляция

WireGuard работает поверх UDP и добавляет к исходному пакету фиксированный набор полей. Точный формат сообщения данных определён в спецификации протокола WireGuard на wireguard.com/protocol; в RFC он не описан. По этой спецификации сообщение данных содержит 16 байт заголовка (1 байт типа, 3 байта резерва, 4 байта индекса получателя, 8 байт счётчика) и 16 байт тега аутентификации Poly1305, то есть 32 байта служебных полей на каждое сообщение данных. Эти цифры стоит сверять с первоисточником, а не со сторонними пересказами: в части публикаций встречаются устаревшие или неверные значения.

Дальше добавляются заголовки транспорта. UDP даёт 8 байт. Внешний IP-заголовок даёт 20 байт для IPv4 (RFC 791) и 40 байт для IPv6 (RFC 8200, базовый заголовок без расширений). Складываем:

Внешний транспортIP-заголовокUDPWireGuardИтого overhead
IPv42083260 байт
IPv64083280 байт

Ключевой момент: overhead считается по внешнему транспорту, а не по внутреннему. Если туннель несёт IPv4-трафик, а внешний канал работает по IPv6, overhead всё равно 80 байт. Внутренняя версия IP меняет только размер полезной нагрузки, но не накладные расходы инкапсуляции. Дополнительные обёртки на пути (PPPoE, VLAN, GRE, IPsec поверх WireGuard) увеличивают реальный overhead сверх этих 60 или 80 байт, и их нужно вычитать отдельно.

Path MTU Discovery: как он должен работать и почему ломается

PMTUD описан в RFC 1191 для IPv4 и в RFC 8201 для IPv6. Механизм прост. Отправитель помечает пакеты флагом DF (Don't Fragment) и не даёт фрагментировать их по пути. Если маршрутизатор не может пропустить пакет, потому что тот больше MTU следующего канала, он отбрасывает его и возвращает отправителю ICMP-сообщение с указанием нужного размера. Отправитель уменьшает пакет и повторяет отправку. Так узел постепенно находит минимальный MTU на всём маршруте.

Схема разваливается в двух случаях. Первый: ICMP блокируется, и узел молча отбрасывает пакеты, не сообщая причину. Второй: ICMP теряется или фильтруется по пути, например на NAT или в туннеле. WireGuard не выполняет PMTUD самостоятельно, поэтому всю работу делает IP-стек, а он зависит от доступности ICMP. Для UDP-протоколов, включая QUIC, MSS clamping не поможет, там размер задаёт само приложение.

ICMP Fragmentation Needed и Packet Too Big: почему их блокировка опасна

Критичны два конкретных сообщения:

  • Для IPv4: ICMP Type 3 Code 4 (Fragmentation Needed and DF set). Именно оно говорит отправителю уменьшить пакет.
  • Для IPv6: ICMPv6 Type 2 (Packet Too Big) с полем MTU следующего канала.

Без этих сообщений отправитель не узнает о необходимости уменьшить размер и будет повторять отправку слишком больших пакетов. Пример: на пути стоит узел с MTU 1400, а отправитель шлёт пакеты 1500 с DF. Узел отбрасывает пакет и должен вернуть ICMP с числом 1400. Если ICMP заблокирован, отправитель зацикливается на повторах, и соединение зависает. Проверьте правила фаервола: пропуск ICMP Type 3 Code 4 для IPv4 и ICMPv6 Type 2 обязателен. Полный набор базовых проверок IP, DNS, маршрутов и MTU собран в шпаргалке по сетевой диагностике.

MSS clamping как обходной путь для PMTUD

Когда PMTUD недоступен, размер TCP-сегментов можно ограничить принудительно. Поле MSS (Maximum Segment Size) описано в RFC 879 и задаёт максимальный объём данных в одном TCP-сегменте без учёта заголовков IP и TCP. Правило на маршрутизаторе переписывает это поле в проходящих SYN-пакетах так, чтобы итоговый сегмент укладывался в MTU пути.

iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu

Ключ --clamp-mss-to-pmtu заставляет ядро подставить MSS, вычисленный из MTU выходного интерфейса. Для ручного значения применяют --set-mss 1360, где 1360 = 1440 (MTU туннеля) минус 20 (IP) минус 20 (TCP) в случае IPv4. Ограничение работает только для TCP. Для UDP, включая QUIC, оно бесполезно, поэтому там размер пакета приходится задавать в самом приложении или уменьшать MTU интерфейса.

Диагностика MTU в WireGuard: команды и практические примеры

План проверки идёт от интерфейсов к маршруту, затем к трафику:

  1. Посмотреть текущий MTU туннеля:
    ip link show wg0
  2. Сравнить с MTU физического интерфейса:
    ip link show eth0
  3. Найти максимальный проходящий пакет командой ping с флагом DF.
  4. Пройти маршрут до цели и увидеть MTU на промежуточных узлах.
  5. Снять трафик и проверить наличие ICMP и фрагментов.
  6. Оценить счётчики передачи на интерфейсе WireGuard.

Поиск оптимального MTU с помощью ping и tracepath

Методика простая: начинайте с размера, который заведомо соответствует MTU 1500, и уменьшайте на 8 байт, пока ping не пройдёт. Формула: размер данных = MTU минус заголовок IP минус заголовок ICMP (8 байт). Для IPv4 заголовок 20 байт, поэтому 1500 - 20 - 8 = 1472.

ping -M do -s 1472 8.8.8.8

Если ping с 1472 не проходит, а с 1464 проходит, то MTU на пути = 1464 + 28 = 1492 (числа 20 и 8 в сумме дают 28). Для IPv6 заголовок 40 байт, поэтому проверка начинается с 1452:

ping -6 -M do -s 1452 2001:4860:4860::8888

Готовый способ увидеть MTU по хопам — tracepath. Утилита сама подбирает размеры и печатает найденный MTU для каждого узла:

tracepath -n 8.8.8.8

Учтите: часть маршрутизаторов не отвечает на ICMP, поэтому tracepath покажет не все хопы, а поле MTU может остаться пустым. Флаги различаются по системам: в Linux это -M do, в macOS -D. Если ICMP заблокирован полностью, ping не годится, тогда для оценки полосы и стабильности применяют TCP-проверки с ограничением скорости.

Анализ трафика через tcpdump: фрагментация и ICMP

Снять ICMP и фрагменты на внешнем интерфейсе можно фильтром по флагам фрагментации. Поле ip[6:2] содержит смещение фрагмента и флаг MF, маска 0x1fff оставляет смещение:

tcpdump -i eth0 -n -v 'icmp or (ip[6:2] & 0x1fff != 0)'

Если в выводе появляется ICMP Fragmentation Needed, значит PMTUD работает и проблема решается уменьшением MTU. Если фрагменты (флаг MF или ненулевое смещение) видны в большом количестве, фрагментация включена и снижает производительность. Смотреть нужно именно на внешний интерфейс, потому что на wg0 трафик уже инкапсулирован в UDP, и фильтр по IP-фрагментам покажет не всю картину. Для просмотра именно инкапсуляции фильтруйте по UDP-порту WireGuard (по умолчанию 51820):

tcpdump -i eth0 -n udp port 51820

Статистику передачи и приёма даёт команда wg show. Рост счётчика transfer без ответов на стороне получателя косвенно указывает на потери крупных пакетов:

wg show

Выбор MTU для WireGuard: IPv4, IPv6 и типовые сценарии

MTU интерфейса WireGuard должен быть таким, чтобы после инкапсуляции итоговый пакет не превышал MTU физического канала. Формулы прямо следуют из overhead:

  • Транспорт IPv4: MTU_wg = MTU_физ - 60.
  • Транспорт IPv6: MTU_wg = MTU_физ - 80.

Нижняя граница для IPv6 задана в RFC 8200: минимальный MTU канала 1280 байт, и опускаться ниже нельзя. При транспорте IPv6 и MTU 1500 значение 1420 остаётся выше этого порога с запасом.

Расчёт MTU для IPv4 и IPv6: формулы и примеры

Для транспорта IPv4 при физическом MTU 1500: 1500 - 60 = 1440. Для транспорта IPv6: 1500 - 80 = 1420. Если канал работает через PPPoE, физический MTU обычно 1492, тогда для IPv4 получаем 1492 - 60 = 1432. Мобильные сети нередко дают MTU 1400, и для IPv4 это 1400 - 60 = 1340. Внутренняя версия IP на значение overhead не влияет, но пакет с IPv6-заголовком внутри требует места под 40 байт заголовка, поэтому при равном MTU туннеля полезная нагрузка для IPv6 меньше.

СценарийMTU каналаТранспортСтартовый MTU WireGuard
Ethernet1500IPv41440
Ethernet1500IPv61420
PPPoE1492IPv41432
Мобильный интернет1400IPv41340

Это стартовые значения, а не догма. Каждое нужно подтвердить ping с флагом DF. Слишком маленький MTU снижает пропускную способность и увеличивает долю служебных байт, слишком большой вызывает фрагментацию или black hole. Как эти значения увязаны со скоростью туннеля, разобрано в руководстве по ускорению VPN и оптимизации MTU.

Настройка MTU на роутере и в конфигурации WireGuard

В wg-quick значение задаётся в секции [Interface]:

[Interface]
PrivateKey = ...
Address = 10.10.0.2/24
MTU = 1440

На роутерах с OpenWrt параметр прописывается в /etc/config/network в секции интерфейса WireGuard:

option mtu '1440'

На стороне сервера WireGuard значение добавляют в wg0.conf в секцию [Interface], после чего перезапускают интерфейс. Дополнительно на шлюзе включают MSS clamping правилом из раздела выше, чтобы TCP-соединения не зависали при крупных передачах. На части устройств (Keenetic, MikroTik) параметр может называться иначе или задаваться в профиле соединения, поэтому сверяйтесь с документацией конкретной модели. После любого изменения MTU обязательно проверяйте соединение ping с флагом DF и реальной передачей файла. Специфику IPv6-туннелей и Dual-Stack удобно смотреть в отдельном материале про VPN-туннели с IPv6.

Типичные ошибки и как их избежать

Большинство проблем с MTU в WireGuard сводится к нескольким повторяющимся ошибкам:

  • MTU 1500 на интерфейсе WireGuard без учёта overhead. Любой крупный пакет получает дополнительно 60-80 байт и вылезает за MTU канала, что даёт фрагментацию или потери. Ставьте расчётное значение, обычно 1440 для IPv4 и 1420 для IPv6.
  • Слишком маленький MTU, например 1280 на IPv4-канале. Пропускная способность падает, потому что растёт доля заголовков в каждом пакете. Уменьшайте значение только до подтверждённого минимума на пути.
  • Блокировка ICMP целиком. Это рвёт PMTUD и приводит к black hole. Пропускайте ICMP Type 3 Code 4 и ICMPv6 Type 2 минимум.
  • Отсутствие MSS clamping на шлюзе. TCP-соединения зависают при передаче данных, хотя handshake проходит. Добавьте правило TCPMSS.
  • Игнорирование IPv6. Заголовок в 40 байт вместо 20 меняет расчёт, а минимальный MTU 1280 ограничивает диапазон снизу.
  • Jumbo frames (MTU 9000) без поддержки на всём пути. Если хотя бы один узел режет пакеты до 1500, крупные кадры фрагментируются или теряются.

Общий принцип: меняйте одно значение за раз и сразу проверяйте результат. Регрессию по задержкам и потерям на разных участках помогает ловить материал про оптимизацию сети для высокодоступных сервисов.

Почему не существует универсального MTU

Итоговое значение зависит от внешнего транспорта (IPv4 или IPv6), наличия дополнительных инкапсуляций (PPPoE, VLAN, GRE), MTU на промежуточных узлах и настроек провайдера. У одного канала MTU 1500, у другого 1480 из-за PPPoE, у третьего 1400 в мобильной сети. Даже в одной сети крупные пакеты могут идти разными маршрутами, и рабочий MTU меняется в зависимости от выбранного пути. Поэтому значение подбирают экспериментально и периодически перепроверяют, а не копируют из статьи или форума.

Проверка числовых утверждений по авторитетным источникам

Все расчёты в статье опираются на стандарты и официальную документацию. Проверить цифры можно по первоисточникам:

  • RFC 791 — заголовок IPv4, базовый размер 20 байт.
  • RFC 8200 — заголовок IPv6, базовый размер 40 байт и минимальный MTU канала 1280 байт.
  • RFC 1191 — Path MTU Discovery для IPv4 и сообщение Fragmentation Needed.
  • RFC 8201 — Path MTU Discovery для IPv6 и сообщение Packet Too Big.
  • RFC 879 — поле TCP MSS и ограничение размера сегмента.
  • Спецификация протокола WireGuard на wireguard.com/protocol — формат сообщений данных и 32 байта служебных полей.

Размер overhead WireGuard (16 байт заголовка плюс 16 байт тега аутентификации) сверяйте с описанием протокола, а не со сторонними пересказами: в части публикаций встречаются устаревшие или неверные цифры. Складывайте накладные расходы вашей конкретной цепочки каналов, иначе расчёт для PPPoE или GRE даст смещённое значение. Проверка любого утверждения начинается с первоисточника, а не с блога.

Отдельно стоит учитывать, что часть бесплатных VPN-сервисов работает на протоколах OpenVPN и WireGuard, которые в России распознаются и блокируются, а перегруженные серверы добавляют собственные потери и задержки (как зарабатывает бесплатный VPN и чем это грозит). Такие сбои легко спутать с проблемой MTU, поэтому при диагностике сначала проверяйте сам канал и стабильность сервера, а уже потом размер пакетов.

Поделиться:
Сохранить гайд? В закладки браузера