Почему VPN умирает при работе с UDP: разбор QoS и MTU
Содержание
- Суть проблемы
- Как работают очереди на маршрутизаторах
- MTU и фрагментация — тихий убийца
- Как проверить MTU
- Настройка MTU в WireGuard
- QoS-маркировка — ваш друг
- Настройка DSCP
- Реальный кейс: офисная сеть
- Кейс: домашний роутер
- Кейс: мобильный оператор
- Что делать с OpenVPN
- Инструменты диагностики
- Настройка через sysctl
- Провайдер душит VPN — что делать
- Протоколы и их поведение
- Настройка серверной части
- Итоговая схема настройки
- Проверка после настройки
- Резюме
Суть проблемы
VPN-туннель работает — и вдруг всё пропало. Пинг идёт, но пакеты с данными не проходят. Или проходят, но с дикими задержками. Знакомая картина? Скорее всего, вы упёрлись в две вещи: QoS-деприоритизацию UDP-трафика и фрагментацию на уровне MTU.
UDP не имеет механизма восстановления. Потерял пакет — всё, данные ушли в никуда. TCP хотя бы перешлёт. А тут — тишина. Особенно это заметно в WireGuard, где весь трафик идёт по UDP.
Как работают очереди на маршрутизаторах
Ваш домашний роутер, корпоративный файрвол, оборудование провайдера — всё это имеет очереди. Пакеты стоят в очереди и ждут отправки. Когда очередь переполняется — пакеты выбрасываются.
Тут вступает в игру QoS. Маршрутизатор смотрит на заголовки пакетов и решает: кому жить, а кому умереть. UDP-трафик от VPN часто помечается как низкоприоритетный. Почему? Потому что провайдеры считают, что UDP — это стриминг, торренты или VoIP. А это — нагрузка на сеть.
Пример: у вас канал 100 Мбит/с. Вы скачиваете торрент — это TCP, он адаптируется. А ваш WireGuard-туннель шлёт UDP-пакеты. Роутер видит UDP — и режет его до 10 Мбит/с. VPN работает, но скорость — как через dial-up.
MTU и фрагментация — тихий убийца
MTU — максимальный размер пакета, который может пройти через интерфейс без фрагментации. Стандарт для Ethernet — 1500 байт. Но VPN добавляет свои заголовки.
WireGuard: 60 байт на заголовок. OpenVPN: до 80 байт. IPSec: 50-60 байт. Итого — если ваш пакет 1500 байт, то внутри туннеля он становится 1560. А это уже больше, чем MTU.
Что происходит? Пакет фрагментируется. Роутер режет его на куски. Каждый кусок отправляется отдельно. Потеряли один кусок — потеряли весь пакет. А с учётом QoS, который и так не любит UDP... Получаем полный отказ.
Как проверить MTU
Не гадайте. Проверяйте.
```bash
ping -M do -s 1472 8.8.8.8
```
Флаг `-M do` запрещает фрагментацию. Размер 1472 — это 1500 минус 28 байт заголовка ICMP. Если пинг проходит — MTU 1500 доступен. Нет — уменьшайте.
Для WireGuard есть более точный метод:
```bash
wg show
```
Смотрим на `transfer` и `received`. Если передача растёт, а получение стоит на месте — проблема с MTU.
Настройка MTU в WireGuard
В конфиге WireGuard можно задать MTU напрямую:
```ini
[Interface]
PrivateKey = ваш_ключ
Address = 10.0.0.2/24
MTU = 1420
```
Почему 1420? Это 1500 минус 80 байт на заголовки WireGuard. Безопасный вариант. Но можно подобрать точнее.
На Linux можно проверить оптимальный MTU:
```bash
ping -M do -s 1392 10.0.0.1
```
Если пакет 1392 проходит, а 1400 нет — ставьте MTU 1420. Запас в 28 байт на заголовки IP.
QoS-маркировка — ваш друг
Проблема QoS решается маркировкой пакетов. В WireGuard можно задать fwmark:
```ini
[Interface]
PrivateKey = ваш_ключ
Address = 10.0.0.2/24
MTU = 1420
Table = off
PostUp = wg set %i fwmark 0x1234
```
А затем настроить правила маршрутизации:
```bash
ip rule add not fwmark 0x1234 table 100
ip route add default via 192.168.1.1 table 100
```
Это заставит пакеты WireGuard идти по отдельному маршруту, минуя очереди, которые душат UDP.
Для OpenVPN есть опция `mark`:
```
mark 0x1234
```
Но это работает только на Linux.
Настройка DSCP
DSCP — поле в заголовке IP, которое говорит маршрутизатору о приоритете. Вы можете выставить его вручную.
Для WireGuard на Linux:
```bash
iptables -t mangle -A OUTPUT -p udp --dport 51820 -j DSCP --set-dscp 46
```
DSCP 46 — это Expedited Forwarding. Максимальный приоритет. Но осторожно: некоторые провайдеры сбрасывают такие метки. Проверяйте на практике.
Реальный кейс: офисная сеть
Был у меня клиент — офис на 50 человек. Все работают через WireGuard-туннель к серверу в другом городе. Всё работало, пока не начали проводить видеоконференции.
Симптомы: пинг до сервера 30 мс, но скорость — 2 Мбит/с вместо 50. Работать невозможно.
Диагностика: проверил MTU. Оказалось — PPPoE-подключение, MTU 1492. А WireGuard с MTU 1420 — всё равно фрагментировался, потому что добавил свои заголовки поверх.
Решение: выставил MTU 1400 в конфиге WireGuard. Проблема ушла. Но через неделю вернулась — провайдер включил QoS, который резал UDP-трафик.
Победили маркировкой DSCP. В итоге — стабильные 45 Мбит/с через туннель.
Кейс: домашний роутер
Другой случай. Домашний роутер Asus с прошивкой Merlin. WireGuard-туннель к VPS. Скорость — 30 Мбит/с при канале 100.
Проблема оказалась в том, что роутер обрабатывал UDP-трафик через software-очередь. Аппаратное ускорение (NAT acceleration) не работало для VPN-трафика.
Решение: отключил аппаратное ускорение для WireGuard-интерфейса. Скорость выросла до 80 Мбит/с. Но пинг подрос с 15 до 25 мс.
Кейс: мобильный оператор
Мобильные сети — отдельная песня. Операторы агрессивно режут UDP. Особенно если видят VPN-трафик.
Симптомы: на 4G VPN работает, но каждые 5-10 минут — обрыв на 30-60 секунд.
Причина: оператор сбрасывает UDP-пакеты, которые идут без активности больше N секунд. WireGuard держит соединение, но если трафика нет — оператор убивает сессию.
Решение: включил PersistentKeepalive в WireGuard:
```ini
[Peer]
PublicKey = ключ_сервера
AllowedIPs = 0.0.0.0/0
Endpoint = сервер:51820
PersistentKeepalive = 25
```
Каждые 25 секунд — пакет поддержания. Оператор видит активность и не убивает сессию.
Что делать с OpenVPN
OpenVPN на UDP — та же история. Но есть особенности.
Во-первых, OpenVPN добавляет больше заголовков. MTU считается так:
```
MTU = 1500 - 20 (IP) - 8 (UDP) - 32 (OpenVPN) = 1440
```
Но лучше проверить:
```bash
openvpn --mtu-test --remote server_ip
```
Во-вторых, OpenVPN поддерживает `mssfix`:
```
mssfix 1360
```
Это ограничивает размер TCP-сегментов внутри туннеля. Полезно, когда MTU нестабилен.
Инструменты диагностики
`mtr` — лучший друг при диагностике сетевых проблем:
```bash
mtr -u -c 100 10.0.0.1
```
Флаг `-u` — UDP. Покажет, где теряются пакеты.
`tcpdump` для анализа:
```bash
tcpdump -i eth0 udp port 51820 -w wireguard.pcap
```
Смотрим на размер пакетов. Если видите пакеты больше 1400 байт — фрагментация.
Настройка через sysctl
На Linux можно настроить буферы и таймауты:
```bash
net.core.rmem_max = 26214400
net.core.wmem_max = 26214400
net.ipv4.udp_mem = 65536 131072 262144
```
Это увеличит буферы для UDP. Помогает, когда пакеты теряются из-за переполнения очередей.
Провайдер душит VPN — что делать
Если провайдер агрессивно режет UDP, есть варианты:
1. Перейти на TCP. OpenVPN поддерживает TCP. WireGuard — нет, но можно завернуть в udp2raw или obfs4.
2. Использовать UDP с меньшим размером пакетов. Ставьте MTU 1280 — минимальный для IPv6, но работает и для IPv4.
3. Шифровать трафик так, чтобы провайдер не мог определить, что это VPN. WireGuard легко детектится по заголовкам. А вот OpenVPN с `--tls-crypt` — сложнее.
Протоколы и их поведение
| Протокол | Заголовок | Типичный MTU | Устойчивость к потерям |
|----------|-----------|--------------|----------------------|
| WireGuard | 60 байт | 1420 | Низкая |
| OpenVPN UDP | 32 байта | 1440 | Средняя |
| IPSec | 50-60 байт | 1400 | Средняя |
| SSTP | TCP | 1460 | Высокая |
Настройка серверной части
На сервере тоже надо настраивать. Если сервер за NAT — открывайте порты. И проверяйте, не режет ли ваш хостинг UDP.
На VPS с Ubuntu:
```bash
iptables -A INPUT -p udp --dport 51820 -j ACCEPT
```
И не забывайте про `/etc/sysctl.conf`:
```
net.ipv4.conf.all.rp_filter = 0
net.ipv4.conf.default.rp_filter = 0
```
Это отключит reverse path filtering, который может блокировать пакеты при асимметричной маршрутизации.
Итоговая схема настройки
Полный рабочий конфиг WireGuard для проблемной сети:
```ini
[Interface]
PrivateKey = ключ
Address = 10.0.0.2/24
MTU = 1380
Table = off
PostUp = wg set %i fwmark 0x1234
PostUp = iptables -t mangle -A OUTPUT -p udp --dport 51820 -j DSCP --set-dscp 46
[Peer]
PublicKey = ключ_сервера
AllowedIPs = 0.0.0.0/0
Endpoint = сервер:51820
PersistentKeepalive = 25
```
MTU 1380 — компромисс. Почти везде работает. DSCP 46 — попытка повысить приоритет. fwmark — для маршрутизации.
Проверка после настройки
Проверяем скорость:
```bash
iperf3 -u -c 10.0.0.1 -b 100M
```
Смотрим потери:
```bash
netstat -s | grep -i "udp"
```
Считаем ошибки. Если потери выше 1% — надо копать дальше. Проверяем MTU на всём пути:
```bash
tracepath 10.0.0.1
```
Резюме
UDP-проблемы VPN решаемы. Главное — системный подход. Сначала MTU, потом QoS, потом маркировка. И не забывайте про keepalive — он спасает от обрывов.
Если всё сделано правильно, VPN будет работать стабильно даже на плохих каналах. Но помните: идеальной сети не бывает. Всегда оставляйте запас в настройках.