Как определить PMTU через TCP MSS при асимметричных маршрутах

Представьте, что вы отправляете посылку через несколько почтовых отделений. Каждое из них может разрешить только определённый размер коробки, но вы узнаёте только о последнем пункте в цепочке. Примерно так работает определение PMTU через MSS в TCP – метод удобный, но не всегда точный, особенно если маршруты туда и обратно различаются.

Давайте разберёмся, почему это происходит и как адаптировать подход для реальных сетевых условий.

Как MSS в SYN-ACK отражает MTU и где кроются ловушки

Когда вы устанавливаете TCP-соединение, сервер в SYN-ACK пакете указывает MSS (Maximum Segment Size) – максимальный размер сегмента, который он готов принимать. Это значение вычисляется на основе MTU (Maximum Transmission Unit) его сетевого интерфейса. Например, для Ethernet с MTU 1500 байт MSS будет 1460 (1500 минус 40 байт на IP и TCP заголовки).

Пример извлечения MSS через tcpdump:

tcpdump -i eth0 'tcp[tcpflags] & (tcp-syn|tcp-ack) != 0'

Но здесь есть три нюанса:

  • Асимметричные маршруты. Если путь от клиента к серверу проходит через роутер с MTU 1400, а обратный – через устройство с MTU 1300, MSS из SYN-ACK покажет только MTU сервера (например, 1500), но не учтёт обратный путь.
  • Вмешательство NAT. Некоторые NAPT (Network Address Port Translation) могут менять TCP-заголовки, включая MSS (это, кстати, одна из причин, почему IPv6 изначально не поддерживает NAT).
  • PMTUD ещё не активирован. На этапе handshake механизм Path MTU Discovery не работает – он запускается только при передаче данных.

Кстате, если вы видите в SYN-ACK MSS 1360, это не обязательно означает, что весь путь поддерживает такой размер. Возможно, где-то на обратной дороге стоит роутер с MTU 1400, но другой участок маршрута «срежет» пакеты до 1300 байт.

Ограничения метода и обходные пути

Главная проблема асимметричных маршрутов в том, что TCP MSS даёт информацию только о первом прыжке (первом сетевом интерфейсе) на стороне сервера. Вот как это выглядит на практике:

  1. Клиент → Сервер: MTU маршрута – 1400 байт.
  2. Сервер → Клиент: MTU маршрута – 1300 байт.
  3. Сервер отправляет SYN-ACK с MSS 1460 (исходя из своего локального MTU 1500).
  4. Клиент считает, что может отправлять сегменты размером 1460 байт, но на обратном пути пакеты >1300 байт будут фрагментированы или отклонены.

Решение? Полагаться не только на MSS, но и на PMTUD (Path MTU Discovery). Вот как это работает:

  • После установки соединения отправляйте пакеты с флагом DF (Don’t Fragment).
  • Если промежуточный роутер обнаруживает, что пакет превышает его MTU, он отправляет ICMP-сообщение «Fragmentation Needed».
  • Клиент уменьшает MTU и повторяет отправку.
Пример настройки PMTUD в Linux:  
sysctl -w net.ipv4.ip_no_pmtu_disc=0 # Включить PMTUD
sysctl -w net.ipv4.tcp_mtu_probing=1 # Автоматический поиск MTU

Важно: если сеть блокирует ICMP (частая ошибка!), PMTUD ломается. В таких случаях выручает MSS Clamping – принудительное ограничение MSS на firewall. Например, для iptables:

iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss 1300

Практические рекомендации для начинающих

Если вы только разбираетесь в тонкостях сетевых протоколов, запомните три правила:

СитуацияЧто делать
Сеть разрешает ICMPПолагайтесь на PMTUD + MSS из SYN-ACK
ICMP заблокированВручную настройте MSS Clamping
Сложные асимметричные маршрутыИспользуйте инструменты вроде tracepath или ping с опцией -s для проверки MTU

Пример проверки PMTU через tracepath:

tracepath -n 8.8.8.8

И ещё: если ваше приложение чувствительно к задержкам (например, VoIP), установите MTU вручную на 100-200 байт меньше стандартного. Это снизит риск фрагментации, даже если где-то в пути окажется «узкое» звено. Помните, что идеального метода нет – только комбинация подходов даёт стабильный результат.

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

Все поля обязательны к заполнению. Ваш адрес email не будет виден никому.

Новое
Интересное