Проверка MTU:
ping -M do -s 1472 8.8.8.8
Если пакеты не проходят — включай Clamping. На Linux:
iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN \
-j TCPMSS --clamp-mss-to-pmtu
На MikroTik:
/ip firewall mangle
add chain=forward protocol=tcp tcp-flags=syn \
action=change-mss new-mss=clamp-to-pmtu
Симптомы: узнаёшь себя?
Не лезь в теорию, пока не сверился со списком. Если хотя бы один пункт совпадает — ты по адресу.
- Ping на 8.8.8.8 проходит, сайты не открываются. Или открываются частично — шапка есть, контент не грузится
- VPN поднялся, IP получен, handshake прошёл — но браузер крутит загрузку и молчит
- Маленькие страницы работают. Большие — нет. Картинки не грузятся, текст есть
- Через мобильный интернет всё летает. Через домашний роутер — не работает ничего
- После подключения PPPoE большие команды в SSH зависают. Маленькие — ок
- OpenVPN или WireGuard поднялся — но браузер пустой
- HTTPS не работает, HTTP иногда работает. Или наоборот — зависит от фазы луны
Всё это — одна болезнь. MTU mismatch. Лечится одним способом — MSS Clamping. Читай дальше.
MTU и MSS: два числа, один смысл
MTU (Maximum Transmission Unit) — максимальный размер пакета на уровне L2/L3. Ethernet: 1500 байт. PPPoE отъедает 8 байт на свой заголовок — остаётся 1492. WireGuard отъедает ещё больше. Каждый туннель — это минус несколько байт к MTU.
MSS (Maximum Segment Size) — максимальный размер TCP-данных в одном сегменте. Без IP и TCP заголовков. Формула одна на всю жизнь:
MSS = MTU - 20 (IP-заголовок) - 20 (TCP-заголовок)
MSS = MTU - 40
Стандартный Ethernet:
MSS = 1500 - 40 = 1460 байт
PPPoE:
MSS = 1492 - 40 = 1452 байт
WireGuard (типичный):
MSS = 1420 - 40 = 1380 байт
MSS передаётся в SYN-пакете при установке соединения. Клиент говорит серверу: «не шли мне сегменты больше X байт». Сервер отвечает своим значением. Оба берут меньшее — и работают с ним.
Вот тут важно: MSS договаривается один раз, в самом начале. Если где-то на пути есть звено с меньшим MTU — и никто об этом не знает — начинается то, что ты сейчас читаешь эту статью.
Почему PMTUD не работает — и при чём тут ICMP
В теории есть механизм Path MTU Discovery. Должен сам находить минимальный MTU на всём пути. Работает через ICMP: если пакет слишком большой для какого-то звена — роутер отправляет ICMP Fragmentation Needed (Type 3, Code 4) и сообщает максимальный размер.
Звучит хорошо. На практике — ломается постоянно. Причина банальная: кто-то заблокировал ICMP.
Кто-то режет весь ICMP «из соображений безопасности» — и не думает что сломал PMTUD. Кто-то пропускает ping (Echo/Reply) но режет Type 3 Code 4 — именно тот который нужен. Это называется ICMP Black Hole. Дыра, в которую падают твои соединения.
Итог: отправитель шлёт пакет 1500 байт. Роутер на PPPoE-участке видит — не пролезет в 1492. Пытается отправить ICMP Fragmentation Needed. Пакет дропается по дороге. Отправитель ничего не знает. Продолжает слать 1500-байтные пакеты. Они продолжают дропаться. Соединение висит.
Поэтому ping работает — ICMP Echo маленький, влезает везде. А большие страницы не открываются — TCP-сегменты данных не влезают, и никто никому об этом не говорит. Всё не так плохо как ты думаешь. Всё намного хуже — потому что диагностировать это без понимания механики почти невозможно.
Что делает MSS Clamping — и почему это работает
MSS Clamping — workaround для сломанного PMTUD. Роутер перехватывает SYN-пакет в самом начале TCP-соединения и уменьшает MSS до безопасного значения. До того как пошли данные.
Четыре вещи которые нужно понять:
- Роутер не фрагментирует пакеты — он предотвращает их появление. Уменьшает MSS на этапе согласования, до передачи данных
- Сервер получает урезанный MSS и думает что клиент сам его предложил. Никого не обманывают — просто подсказывают правильное число
- Ни клиент, ни сервер не знают о Clamping — операция прозрачная
- Срабатывает один раз на соединение — в SYN. Данные роутер не трогает
Как это работает на уровне TCP handshake
Смотри по шагам — что происходит когда на роутере настроен Clamping:
- Клиент отправляет SYN с
MSS=1460— стандарт для Ethernet - Роутер перехватывает SYN. Видит: MSS=1460, но туннель позволяет только 1380. Надо исправить
- Роутер переписывает MSS прямо в пакете:
MSS=1380 - Сервер получает SYN с
MSS=1380— думает что клиент сам так захотел - Сервер отвечает SYN-ACK со своим MSS. Роутер при необходимости урезает и его
- Клиент отправляет ACK — соединение установлено
- Все сегменты данных теперь ≤ 1380 байт. В туннель влезают. Интернет работает
Почему именно SYN? Потому что MSS передаётся только в SYN и SYN-ACK. После этого оба конца уже договорились — менять нечего.
Когда без Clamping не обойтись
Три схемы — наглядно показывают разницу.
Схема 1: без MSS Clamping — пакет дропается
Схема 2: с MSS Clamping — пакет проходит
Схема 3: TCP handshake с подменой MSS
ACK в третьем шаге MSS не содержит — Clamping к нему не применяется. MSS передаётся только в SYN и SYN-ACK. Запомни раз и навсегда.
Список сценариев где Clamping обязателен — не опционален, а обязателен:
- PPPoE — самый частый случай. PPPoE съедает 8 байт заголовка, MTU падает с 1500 до 1492. MSS должен быть 1452 или ниже
- OpenVPN — overhead: UDP + OpenVPN-заголовок + шифрование. Типичный MTU внутри туннеля: 1400–1440
- WireGuard — overhead около 60 байт на IPv4. Рекомендованный MTU внутри: 1420
- IPsec/GRE — GRE добавляет 24 байта, ESP ещё больше. MTU зависит от алгоритма шифрования
- VXLAN / облачные сети — AWS, GCP, Azure используют VXLAN с overhead 50+ байт. Без Clamping часть трафика в облачных VPC тихо дропается
- CGNAT / DS-Lite — двойной NAT у мобильных операторов и кабельщиков добавляет ещё один слой инкапсуляции
- Туннель поверх туннеля — каждый слой отъедает MTU. Чем глубже в туннели, тем меньше остаётся
MSS Clamping на Linux через iptables
Самый распространённый вариант. Работает на любом Linux-роутере, VPS-шлюзе, OpenWrt. Одна команда решает проблему.
Базовая команда
iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN \
-j TCPMSS --clamp-mss-to-pmtu
Разбор — потому что понимать важнее чем копировать:
-t mangle— таблица mangle. Не filter (там фильтруют), не nat (там адреса меняют). Mangle — для модификации полей пакета. Именно сюда-A FORWARD— цепочка FORWARD. Для пакетов которые проходят через роутер транзитом. Напишешь INPUT или OUTPUT — не сработает для клиентов за роутером. Классическая ошибка-p tcp --tcp-flags SYN,RST SYN— только TCP с флагом SYN и без RST. Именно первый SYN при установке соединения-j TCPMSS --clamp-mss-to-pmtu— ядро само вычисляет PMTU для исходящего интерфейса и ставит MSS = PMTU — 40. Не угадывай значение — пусть считает сам
Если нужно зафиксировать конкретное значение
# Вместо автоматического clamp-to-pmtu - конкретное значение
iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN \
-j TCPMSS --set-mss 1360
# Для PPPoE (MTU 1492):
iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN \
-j TCPMSS --set-mss 1452
# Для WireGuard (MTU 1420):
iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN \
-j TCPMSS --set-mss 1380
Применить только на конкретном интерфейсе
# Только для трафика уходящего в туннель WireGuard
iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN \
-o wg0 -j TCPMSS --clamp-mss-to-pmtu
# Для PPPoE
iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN \
-o ppp0 -j TCPMSS --clamp-mss-to-pmtu
Указывать -o ИНТЕРФЕЙС — правильная практика. Меньше побочных эффектов чем вешать правило на весь FORWARD без фильтрации.
Сохранить после перезагрузки
apt install iptables-persistent -y
iptables-save > /etc/iptables/rules.v4
Или добавь в post-up скрипт туннеля — WireGuard и OpenVPN оба это поддерживают.
MSS Clamping в nftables
nftables — замена iptables по умолчанию в Debian 11+, Ubuntu 22.04+. Синтаксис другой, логика та же.
# Создать таблицу и цепочку
nft add table ip mangle
nft add chain ip mangle FORWARD { type filter hook forward priority mangle \; }
# Добавить правило
nft add rule ip mangle FORWARD tcp flags syn tcp option maxseg size set rt mtu
# Проверить
nft list ruleset
Для постоянного применения — в /etc/nftables.conf:
table ip mangle {
chain FORWARD {
type filter hook forward priority mangle; policy accept;
tcp flags syn tcp option maxseg size set rt mtu
}
}
systemctl enable nftables
systemctl restart nftables
MSS Clamping в MikroTik
Через CLI RouterOS:
/ip firewall mangle
add chain=forward protocol=tcp tcp-flags=syn \
action=change-mss new-mss=clamp-to-pmtu \
comment="MSS Clamping"
Через Winbox: IP → Firewall → Mangle → Add. Chain: forward, Protocol: tcp, TCP Flags: syn, Action: change mss, New MSS: clamp to pmtu. Сохранить.
Для PPPoE с фиксированным значением:
/ip firewall mangle
add chain=forward protocol=tcp tcp-flags=syn \
action=change-mss new-mss=1452 \
comment="MSS Clamping PPPoE"
Для WireGuard — указать интерфейс:
/ip firewall mangle
add chain=forward protocol=tcp tcp-flags=syn \
out-interface=wireguard1 \
action=change-mss new-mss=clamp-to-pmtu \
comment="MSS Clamping WireGuard"
Проверить что правило работает — счётчики должны расти при активных соединениях:
/ip firewall mangle print stats
MSS Clamping в Cisco IOS
На интерфейсе куда уходит туннель или PPP:
interface GigabitEthernet0/0
ip tcp adjust-mss 1452
! Для туннельного интерфейса:
interface Tunnel0
ip tcp adjust-mss 1360
ip tcp adjust-mss работает на уровне интерфейса — переписывает MSS в SYN-пакетах в обоих направлениях.
Диагностика: сначала проверь, потом настраивай
Не ставь Clamping наугад. Сначала убедись что проблема именно в MTU.
Тест ping с фиксированным размером
# Linux - не фрагментировать, payload 1472 байта
ping -M do -s 1472 8.8.8.8
# macOS
ping -D -s 1472 8.8.8.8
# Windows
ping -f -l 1472 8.8.8.8
Почему 1472: это 1500 (Ethernet MTU) минус 28 (20 байт IP + 8 байт ICMP). Пакет проходит — Ethernet MTU в порядке. Не проходит — где-то MTU меньше 1500. Ищи туннель.
Бинарный поиск правильного MTU
# Начни с 1472, уменьшай пока не пройдёт
ping -M do -s 1472 8.8.8.8 # MTU 1500
ping -M do -s 1452 8.8.8.8 # MTU 1480 (PPPoE?)
ping -M do -s 1432 8.8.8.8 # MTU 1460
ping -M do -s 1380 8.8.8.8 # MTU 1408 (WireGuard?)
ping -M do -s 1350 8.8.8.8 # MTU 1378
# Автоматически найти максимальный размер:
for size in 1472 1452 1432 1412 1392 1372 1352 1332; do
result=$(ping -M do -s $size -c 1 -W 2 8.8.8.8 2>&1)
if echo "$result" | grep -q "1 received"; then
echo "MTU работает: $((size + 28)) (payload: $size)"
break
else
echo "MTU $((size + 28)) - дроп"
fi
done
tcpdump: смотрим MSS в SYN-пакетах
# Запусти на роутере, потом открой браузер
tcpdump -i eth0 -n 'tcp[tcpflags] & (tcp-syn) != 0' -v | grep "mss"
# Что ищем в выводе:
# "mss 1460" на чистом Ethernet - норма
# "mss 1452" на PPPoE после Clamping - норма
# "mss 1460" на PPPoE - Clamping не работает
Проверить что Clamping сработал
# Счётчики правила - должны расти при открытии новых соединений
iptables -t mangle -L FORWARD -v -n | grep TCPMSS
# Если pkts = 0 - правило не срабатывает
# Причины: не тот интерфейс, не SYN, цепочка FORWARD пустая
Из жизни: WireGuard поднялся, сайты не открываются
Классика жанра. Офис подключён через WireGuard к корпоративному шлюзу. Туннель поднялся, IP получен, ping до внутренних хостов идёт. Открываешь браузер — крутит загрузку, таймаут. Звонок в поддержку: «у нас VPN не работает». По факту — VPN работает. Не работает MSS Clamping.
Что происходит по шагам:
- Клиент внутри туннеля имеет MTU 1420 — WireGuard overhead ~80 байт от 1500
- Клиент шлёт SYN с
MSS=1460— не знает про туннель, живёт в своём Ethernet-мире - Сервер отвечает SYN-ACK, соединение устанавливается с MSS=1460
- Сервер начинает слать TCP-сегменты по 1460 байт
- Пакет с заголовками = 1500 байт. Плюс WireGuard overhead = 1580 байт
- В физический MTU 1500 не влезает. DF-бит установлен — пакет дропается
- ICMP Fragmentation Needed уходит и теряется где-то в firewall провайдера
- Сервер продолжает слать 1460-байтные сегменты. Они продолжают дропаться
- Браузер ждёт. Потом таймаут. Звонок в поддержку
Почему ping работал? ICMP Echo — маленький пакет, влезает с любым overhead. А TCP-сегменты данных — нет.
Решение — одна команда на шлюзе:
# На Linux-шлюзе
iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN \
-o wg0 -j TCPMSS --clamp-mss-to-pmtu
# Или зафиксировать явно: 1420 - 40 = 1380
iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN \
-o wg0 -j TCPMSS --set-mss 1380
После этого все новые TCP-соединения через туннель используют MSS ≤ 1380. Сегменты + заголовки = 1420 байт. WireGuard overhead = ≤ 1500. Всё влезает. Сайты открываются. Звонок в поддержку не состоялся.
Для OpenVPN та же логика: MTU туннеля 1400–1440, MSS = MTU_туннеля — 40, ставишь через --set-mss.
Типичные ошибки — и как их не сделать
iptables -t mangle -L -v | grep TCPMSS
iptables -A INPUT -p icmp --icmp-type destination-unreachable -j ACCEPT
Найти MTU на каждом хопе
Ping не идёт с 1472, но непонятно где именно режется — используй tracepath.
# Linux - tracepath сам определяет MTU на каждом хопе
tracepath -n 8.8.8.8
# В выводе ищи:
# "pmtu 1492" - ограничение 1492, PPPoE
# "pmtu 1420" - ограничение 1420, туннель
# Альтернатива - traceroute без фрагментации:
traceroute -F -m 30 8.8.8.8
# Windows
pathping -n 8.8.8.8
# PowerShell
Test-NetConnection -ComputerName 8.8.8.8 -Port 80
Смотри где трассировка обрывается. Обычно это граница между твоей сетью и провайдером, или вход в туннель.
Справочник: MSS для популярных конфигураций
| Тип подключения | MTU | Overhead | Рекомендованный MSS |
|---|---|---|---|
| Ethernet (стандарт) | 1500 | 0 | 1460 |
| PPPoE | 1492 | 8 | 1452 |
| WireGuard (IPv4) | 1420 | 60+ | 1380 |
| OpenVPN UDP | 1400–1440 | зависит от конфига | 1360–1400 |
| IPsec ESP (AES) | ~1418 | ~82 | 1378 |
| GRE | 1476 | 24 | 1436 |
| VXLAN | 1450 | 50 | 1410 |
| Туннель в туннеле | ~1360 | 140+ | 1320 или ниже |
Значения приблизительные — overhead зависит от конфигурации. Всегда проверяй реальный MTU через ping-тест, не угадывай по таблице.
FAQ
Что такое MSS в TCP?
MSS (Maximum Segment Size) — максимальный размер данных в одном TCP-сегменте. Без IP и TCP заголовков — только payload. Передаётся в SYN-пакете при установке соединения. Для стандартного Ethernet: 1460 байт (1500 MTU минус 40 байт заголовков).
Чем MSS отличается от MTU?
MTU — ограничение на уровне сети, весь пакет включая заголовки. MSS — ограничение на уровне TCP, только данные без заголовков. Связь простая: MTU = MSS + 40. MTU задаётся на интерфейсе, MSS договаривается между двумя хостами при TCP handshake.
Какое значение MSS ставить?
Используй --clamp-mss-to-pmtu — ядро само считает по MTU исходящего интерфейса. Если нужно фиксированное: MTU_туннеля − 40. PPPoE (MTU 1492) → MSS 1452. WireGuard (MTU 1420) → MSS 1380. OpenVPN — узнай реальный MTU через ping и вычти 40.
Зачем Clamping если есть PMTUD?
PMTUD работает через ICMP Type 3 Code 4 (Fragmentation Needed). Этот тип ICMP блокируется повсеместно — намеренно или по незнанию. Без него PMTUD не работает и отправитель никогда не узнает о проблеме. MSS Clamping решает проблему до начала передачи данных — не полагаясь на ICMP вообще.
Clamping влияет на производительность?
Минимально. Правило срабатывает только на SYN — один раз на соединение. Данные не трогает. Единственный риск: если поставить слишком маленький MSS вручную — производительность упадёт из-за мелких сегментов. Используй clamp-to-pmtu и не думай об этом.
Почему через мобильный работает, а через роутер нет?
Мобильные операторы делают MSS Clamping на своей стороне — исторически потому что их сети имели нестандартный MTU и они давно это знают. Твой домашний роутер этого не делает пока ты не настроишь. Добавь Clamping — симптом уйдёт.
Итог
MSS Clamping — одна из тех настроек которую делаешь один раз и забываешь о целом классе проблем. Ping есть, HTTP нет — сразу MTU. VPN поднялся но ничего не работает — сразу Clamping. Рождённый в туннеле без Clamping стабильной работы не видит.
Команда которую нужно помнить наизусть:
iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN \
-j TCPMSS --clamp-mss-to-pmtu
Всё остальное — вариации. Понял механику — не запутаешься ни в MikroTik, ни в Cisco, ни в nftables. Синтаксис разный, смысл один.
Оставайтесь на связи
Рецепты от IT-боли. Без воды, без рекламы, без маркетинговой шелухи.
Подписаться на IT-Аптеку →


