PMTUD
PMTUD (Path MTU Discovery, RFC 1191 для IPv4, RFC 8201 для IPv6) — механизм автоматического обнаружения самого маленького MTU на пути от источника до назначения. Нужен чтобы не фрагментировать пакеты и не резать производительность.
Как работает (IPv4)
- Хост шлёт пакет с флагом Don't Fragment (DF) и размером = локальный MTU (обычно 1500).
- Промежуточный роутер видит: следующий линк имеет MTU=1400, а пакет 1500 с DF.
- Роутер дропает пакет и отвечает ICMP Type 3 Code 4 «Fragmentation Needed» с указанием MTU=1400.
- Отправитель уменьшает свой path-MTU до 1400 для этой цели, повторяет.
- Процесс повторяется пока пакеты не пройдут.
Как работает (IPv6)
В IPv6 роутеры не фрагментируют — только источник. Все пакеты фактически имеют DF=1. Аналог ICMPv4 «Frag Needed» — ICMPv6 Type 2 «Packet Too Big». Механизм проще и надёжнее.
ICMP Black Hole
Многие фаерволы дропают весь ICMP из «безопасности». В результате:
- Отправитель шлёт 1500-байт с DF.
- Роутер дропает и шлёт ICMP «Frag Needed» — но ICMP не доходит.
- Отправитель ждёт таймаута, ретрансмитит.
- Всё повторяется. Соединение висит.
Симптомы: маленькие пакеты (SYN, DNS, HTTP-запросы без данных) проходят, большие — нет. Веб-страницы «загружает» → 0%. TLS-handshake зависает на Certificate.
Решения
1. MSS clamping
Роутер переписывает MSS в SYN-пакетах на меньшее — TCP-стороны сами используют меньше. Не требует ICMP. Работает только для TCP. См. MSS.
2. Разрешить ICMP «Packet Too Big»
В файрволе явно пропустить ICMP Type 3 Code 4 (IPv4) и ICMPv6 Type 2:
iptables -A INPUT -p icmp --icmp-type fragmentation-needed -j ACCEPT
ip6tables -A INPUT -p icmpv6 --icmpv6-type packet-too-big -j ACCEPT
3. PLPMTUD (Packetization Layer PMTUD)
RFC 4821 — не полагается на ICMP. TCP сам тестирует пробующими пакетами разного размера. Если пропало → уменьшает MTU. Полностью работает вне зависимости от блокировки ICMP.
Включено по умолчанию в Linux (net.ipv4.tcp_mtu_probing = 1 с 2007), Windows Vista+, macOS.
4. Ручная настройка MTU
# Уменьшить MTU интерфейса
ip link set eth0 mtu 1400
# Route-specific MTU
ip route add 10.0.0.0/8 via 192.168.1.1 mtu 1400
Как проверить
# ping с DF-битом (Linux)
$ ping -M do -s 1472 example.com
PING example.com (1.2.3.4) 1472(1500) bytes of data.
1480 bytes from 1.2.3.4: icmp_seq=1 ttl=57 time=15.3 ms
# Уменьшаем до 1450
$ ping -M do -s 1450 example.com
PING example.com (1.2.3.4) 1450(1478) bytes of data.
1458 bytes from 1.2.3.4: icmp_seq=1 ttl=57 time=15.5 ms
# Проверить с флагом DF на конкретный размер
# Windows
ping -f -l 1472 example.com
# macOS
ping -D -s 1472 example.com
tracepath — трассировка MTU
$ tracepath example.com
1?: [LOCALHOST] pmtu 1500
1: gw.local 0.5ms
2: isp-gw 10ms pmtu 1492
3: bgp-router 15ms
4: example-router 20ms pmtu 1400
5: example.com 25ms reached
PMTUD и туннели
При инкапсуляции (VXLAN, GRE, IPsec, WireGuard) MTU inner-канала меньше outer. Если PMTUD ломается — приложения внутри туннеля сталкиваются с blackhole.
Best practice — включить MSS clamping на туннельных интерфейсах всегда:
iptables -t mangle -A FORWARD -o wg0 -p tcp --tcp-flags SYN,RST SYN \
-j TCPMSS --clamp-mss-to-pmtu
PMTUD в UDP/QUIC
UDP без сохранения состояния — приложение должно само делать PLPMTUD. QUIC имеет встроенный DPLPMTUD (Datagram PLPMTUD, RFC 8899).