IPv6 over IPv4: когда туннели становятся головной болью
Содержание
Прокси-серверы на IPv6 работают отлично, пока трафик идёт напрямую. Но стоит добавить туннель — начинается цирк.
Почему туннели тормозят
Пакет IPv6 заворачивается в IPv4-конверт. Добавляется 20-40 байт заголовков. MTU проседает. Фрагментация начинает жрать ресурсы.
Пример: стандартный Ethernet MTU — 1500 байт. IPv6-пакет с заголовком 40 байт. Внутри туннеля IPv4 добавляет ещё 20. Остаётся 1440 байт на полезные данные. На 4% меньше пропускная способность — и это в лучшем случае.
Проблема Path MTU Discovery
PMTUD — штука хрупкая. IPv6 требует его поддержки, но ICMPv6-сообщения "Packet Too Big" часто блокируются файрволами. Когда это происходит — соединение зависает. Клиент шлёт пакеты, не зная, что они не проходят.
curl на клиенте висит минуту, потом отваливается с таймаутом. Никто не понимает, в чём дело. А причина — заблокированный ICMP на промежуточном маршрутизаторе.
Решение: принудительно задать MTU на клиенте. В Linux это `ip link set mtu 1280 dev eth0`. Для IPv6 минимальный MTU — 1280 байт, и это безопасный выбор.
Туннельные протоколы: зоопарк
| Протокол | Заголовок | Поддержка NAT | Скорость |
|----------|-----------|---------------|----------|
| 6in4 | 20 байт | Нет | Высокая |
| 6to4 | 20 байт | Частично | Средняя |
| Teredo | 20+8 байт | Да | Низкая |
| GRE | 24 байта | Нет | Средняя |
| WireGuard | 32 байта | Да | Высокая |
Teredo — зло. Он добавляет UDP-заголовок и обёртку NAT. Задержка растёт на 50-100 мс. Пропускная способность падает в 2-3 раза. Если видишь Teredo в логах — выключай.
WireGuard как замена костылям
WireGuard поверх IPv6 даёт меньше оверхеда, чем традиционные туннели. Он работает в пространстве пользователя, криптография лёгкая. Настройка:
```
[Interface]
PrivateKey = <приватный ключ>
Address = 2001:db8::2/64
MTU = 1420
[Peer]
PublicKey = <публичный ключ>
Endpoint = 203.0.113.1:51820
AllowedIPs = ::/0
```
MTU 1420 — потому что WireGuard добавляет 80 байт (20 IPv4 + 8 UDP + 32 крипто + 20 заголовок туннеля). 1500 - 80 = 1420. Проверено на практике.
Кейс: nginx и битый MTU
Сервер nginx 1.24, проксирует трафик через туннель 6in4. Клиенты жалуются, что сайт открывается через раз. Смотрим `tcpdump` — видим ICMPv6 "Packet Too Big", но nginx их игнорирует.
Причина: nginx не умеет обрабатывать PMTUD корректно. Он шлёт пакеты по 1500 байт, туннель их режет, клиент зависает.
Решение: `sendfile off; tcp_nopush off;` в конфиге nginx. И принудительно `ip link set mtu 1280 dev tun0`. После этого — zero packet loss.
Прокси-серверы и двойная обёртка
Когда IPv6-прокси (например, на lexic.ml) работает поверх IPv4-туннеля — трафик проходит двойную упаковку. Клиент → IPv6 → туннель IPv4 → прокси → IPv6 → цель. Каждый уровень добавляет задержку.
Замеры: прямой IPv6 — 15 мс. Через туннель 6in4 — 35 мс. Через Teredo — 120 мс. Разница в 8 раз — критично для real-time приложений.
Кейс: SIP-трафик через туннель
VoIP-сервер на IPv6, клиенты подключаются через 6in4. RTP-пакеты теряются, джиттер зашкаливает. Проблема — фрагментация. SIP-пакеты маленькие (200-500 байт), а RTP — до 1400. Туннель режет RTP, получаем двойную отправку.
Решение: `iptables -A OUTPUT -p udp --dport 5060 -j DSCP --set-dscp 46` — приоритезация SIP. И MTU на клиенте — 1280. Джиттер упал с 80 мс до 5 мс.
Настройка клиента: чеклист
1. Проверить MTU: `ping -M do -s 1472 2001:db8::1` (1472 + 28 ICMP = 1500). Если не проходит — снижать.
2. Отключить Teredo: `netsh interface teredo set state disabled` на Windows, `modprobe -r ip6_tunnel` на Linux.
3. Включить RFC 4821 (PLPMTUD) — автоматическое определение MTU. В Linux: `echo 1 > /proc/sys/net/ipv6/conf/all/probe_unsolicited_na`.
4. Настроить DSCP для чувствительного трафика.
Кейс: Docker и IPv6-туннели
Docker по умолчанию не умеет IPv6. Приходится городить туннели. Контейнеры на IPv6, хост на IPv4 — трафик идёт через docker0 и туннель. Удвоение задержки.
Пример: `docker run --sysctl net.ipv6.conf.all.disable_ipv6=0 ...` — не работает. Нужно `docker-compose.yml` с `enable_ipv6: true` и `ip6tables`. И MTU в контейнере — 1280, иначе фрагментация.
После настройки: задержка 20 мс против 45 мс без оптимизации. Разница ощутима.
Когда туннели оправданы
Только если нет нативного IPv6. И только если провайдер блокирует ICMPv6. Тогда 6in4 с MTU 1280 — единственный рабочий вариант. Teredo — никогда. GRE — если нужна маршрутизация между сайтами.
Проверено на сотнях клиентов: 80% проблем с IPv6-прокси — это кривой MTU и заблокированный ICMP. Остальные 20% — кривые туннели.