Туннелирование IPv6 через IPv4: как работает NAT64 и где оно подводит
Содержание
- Архитектура NAT64: как это устроено
- /etc/tayga.conf
- Запуск
- Префикс 64:ff9b::/96: стандарт и его ограничения
- MTU: первая грабля
- DNS64: обязательный компаньон
- Какие проблемы реально всплывают
- Фрагментация и UDP
- TCP MSS Clamping
- Проблемы с приложениями
- ICMPv6 и ошибки
- Кейс: IPv6-only сеть и старый сервер
- Кейс: DNS64 и недоступный сервер
- Кейс: VoIP и SIP через NAT64
- Таблица сравнения: NAT64 vs туннели
- Когда NAT64 не нужен
- Настройка полного стека
- Tayga
- Маршрут
- DNS64 в BIND
- Итоги
IPv6 существует с 1998 года. Протокол прописан в RFC 2460, потом обновлён в RFC 8200. Но интернет до сих пор сидит на IPv4. Причина простая — NAT. Миллионы устройств за одним белым адресом. Провайдеры не спешат менять инфраструктуру, потому что всё работает.
А когда всё работает — ничего не трогают. Знакомая история.
NAT64 появился как мост между мирами. Позволяет IPv6-клиенту ходить на IPv4-серверы. И наоборот. Но дьявол, как обычно, в деталях.
Архитектура NAT64: как это устроено
NAT64 — это не туннель в классическом понимании. Туннель (6in4, GRE, IPIP) инкапсулирует пакет целиком. NAT64 работает на уровне трансляции адресов. Разбирает заголовок IPv6, вытаскивает payload, заворачивает в IPv4. Механизм описан в RFC 6146.
Схема работы:
```
IPv6-клиент → NAT64-шлюз → IPv4-сервер
2001:db8::1 192.0.2.10
```
Ключевой элемент — префикс NAT64. Обычно это `64:ff9b::/96` из RFC 6052. Но можно назначить свой. Шлюз слушает этот префикс, получает пакеты, транслирует.
Пример на Linux с Tayga:
```bash
/etc/tayga.conf
prefix 2001:db8:64::/96
dynamic-pool 192.0.2.100/24
tun-device nat64
data-dir /var/spool/tayga
Запуск
tayga --mktun
ip link set nat64 up
ip addr add 2001:db8:64::1/96 dev nat64
ip addr add 192.0.2.1/24 dev nat64
tayga
```
Теперь IPv6-клиент с адресом `2001:db8:64::c000:20a` попадёт на IPv4-адрес `192.0.2.10`. Простая арифметика: последние 32 бита IPv6-адреса — это IPv4-адрес назначения.
Префикс 64:ff9b::/96: стандарт и его ограничения
RFC 6052 определяет Well-Known Prefix. Идея хорошая — все NAT64-шлюзы в мире слушают один префикс. Но на практике это создаёт проблемы.
Представьте: у вас два NAT64-шлюза. Оба с `64:ff9b::/96`. Клиент отправляет пакет на `64:ff9b::c000:20a`. Какой шлюз поймает? Тот, который ближе по маршрутизации. Если маршрут не прописан — пакет уйдёт в никуда.
Поэтому на практике используют собственные префиксы. Например, `2001:db8:64::/96`. Это даёт контроль над маршрутизацией. Но ломает совместимость — клиент должен знать префикс конкретного оператора.
MTU: первая грабля
IPv6 имеет MTU 1280 байт минимум. IPv4 — 576. Разница огромная. NAT64-шлюз должен фрагментировать пакеты. Но IPv6 не поддерживает фрагментацию на промежуточных узлах. Только конечные хосты.
Решение — уменьшить MTU на клиенте. Или использовать PLPMTUD (Packetization Layer Path MTU Discovery). На практике многие просто ставят MTU 1280 на IPv6-интерфейсе. Это работает, но теряется производительность.
Пример настройки в Linux:
```bash
ip link set eth0 mtu 1280
```
Проверка:
```bash
ping6 -M do -s 1200 2001:db8:64::c000:20a
```
Если пакет 1200 байт проходит, а 1300 нет — проблема в MTU.
DNS64: обязательный компаньон
NAT64 без DNS64 не работает. Клиент запрашивает AAAA-запись. DNS64-сервер синтезирует её из A-записи. Добавляет префикс NAT64 к IPv4-адресу. Клиент получает IPv6-адрес, отправляет пакет на шлюз.
Настройка BIND с DNS64:
```
options {
dns64 2001:db8:64::/96 {
clients { any; };
mapped { any; };
exclude { 127.0.0.0/8; 10.0.0.0/8; };
};
};
```
Проблема: DNS64 не знает о недоступных IPv4-серверах. Если сервер лежит, клиент получит синтезированный адрес и будет ждать таймаут. Время ожидания TCP в IPv6 — 75 секунд. Пользователь подумает, что сайт умер.
Какие проблемы реально всплывают
Фрагментация и UDP
UDP-пакеты больше MTU IPv4 (576 байт) фрагментируются. NAT64-шлюз должен собрать фрагменты. Это нагрузка на CPU. При DDoS-атаках шлюз захлёбывается.
Тест на фрагментацию:
```bash
ping6 -s 1400 2001:db8:64::c000:20a
```
Если ответа нет, а на 1200 байтах есть — фрагментация сломана.
TCP MSS Clamping
TCP-сегменты с опцией MSS (Maximum Segment Size) должны быть скорректированы. Иначе клиент отправит сегмент 1460 байт, шлюз не сможет его упаковать в IPv4-пакет.
Настройка iptables для clamping:
```bash
iptables -t mangle -A POSTROUTING -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
```
Проблемы с приложениями
Некоторые приложения хранят IP-адреса в данных. FTP — классический пример. Команда PORT передаёт IPv4-адрес в ASCII. NAT64 не знает о прикладном уровне. FTP через NAT64 ломается.
Решение — использовать FTP в пассивном режиме с ALG (Application Layer Gateway). Но ALG — это дополнительный костыль.
ICMPv6 и ошибки
ICMPv6 Type 2 (Packet Too Big) должен транслироваться в ICMPv4 Type 3 Code 4. Многие NAT64-шлюзы не делают этого корректно. В результате клиент не узнаёт о проблемах с MTU.
Проверка:
```bash
ping6 -M do -s 1400 2001:db8:64::c000:20a
```
Если ответ "Packet Too Big" не приходит — шлюз не транслирует ICMP.
Кейс: IPv6-only сеть и старый сервер
Пример: компания перевела офис на IPv6-only. Сервер 1С работает на IPv4. Адрес 10.0.0.5. Через NAT64 сотрудники ходят на него.
Проблема: 1С использует длинные TCP-соединения. NAT64-шлюз держит таблицу трансляции. Таймаут по умолчанию — 60 секунд. Если соединение простаивает дольше — таблица очищается. Пакет приходит, но шлюз не знает, куда его направить. Соединение рвётся.
Решение: увеличить таймаут в Tayga:
```bash
tayga --set-timeout 3600
```
Или настроить keepalive на клиенте:
```bash
sysctl net.ipv4.tcp_keepalive_time=120
sysctl net.ipv4.tcp_keepalive_intvl=30
```
Кейс: DNS64 и недоступный сервер
Сайт компании переехал на IPv6. Но часть поддоменов осталась на IPv4. DNS64 синтезирует AAAA-записи для всех. Один поддомен оказался недоступен — сервер лежит.
Клиент получает AAAA-адрес. Отправляет TCP SYN. Ждёт. 75 секунд. Потом таймаут. Пользователь обновляет страницу — снова 75 секунд. Итог: сайт "не работает", хотя проблема в одном поддомене.
Решение: настроить DNS64 с исключениями. Или использовать fallback на IPv4-доступ через NAT64.
Кейс: VoIP и SIP через NAT64
SIP использует SDP (Session Description Protocol). В нём передаются IP-адреса и порты. NAT64 не умеет их транслировать. Звонки через NAT64 работают только с ALG.
Тест:
```bash
sipsak -s sip:user@example.com -v
```
Если ответ "401 Unauthorized" — SIP-запрос прошёл. Если таймаут — проблема с трансляцией.
Таблица сравнения: NAT64 vs туннели
| Параметр | NAT64 | 6in4 туннель | GRE |
|---|---|---|---|
| Протокол | Трансляция | Инкапсуляция | Инкапсуляция |
| MTU | 1280 байт | 1480 байт | 1476 байт |
| Задержка | +0.1-0.5 мс | +0.5-1 мс | +0.5-1 мс |
| Совместимость | Только IPv6-клиенты | Все | Все |
| NAT на пути | Не нужен | Проблемы | Проблемы |
| Прикладной уровень | Не знает | Не знает | Не знает |
Когда NAT64 не нужен
Если у вас есть белые IPv4-адреса — не мучайтесь. NAT64 добавляет задержку, сложность, точки отказа. Туннель 6in4 проще и надёжнее.
Но если IPv4-адресов нет, а IPv6-only сеть нужна — NAT64 единственный вариант. Плюс DNS64. Плюс ALG для некоторых протоколов.
Настройка полного стека
Для теста на Ubuntu:
```bash
apt install tayga bind9
Tayga
cat > /etc/tayga.conf < prefix 2001:db8:64::/96 dynamic-pool 192.0.2.100/24 tun-device nat64 data-dir /var/spool/tayga EOF tayga --mktun ip link set nat64 up ip addr add 2001:db8:64::1/96 dev nat64 ip addr add 192.0.2.1/24 dev nat64 tayga ip -6 route add 2001:db8:64::/96 dev nat64 cat >> /etc/bind/named.conf.options < dns64 2001:db8:64::/96 { clients { any; }; mapped { any; }; }; EOF systemctl restart bind9 ``` Проверка: ```bash dig AAAA example.com @127.0.0.1 ping6 2001:db8:64::c000:20a ``` NAT64 — рабочий инструмент, но с кучей оговорок. MTU, фрагментация, ICMP, прикладные протоколы — всё это требует внимания. Настроить и забыть не получится. Если выбираете между NAT64 и туннелями — считайте задачи. Для доступа к IPv4-ресурсам из IPv6-only сети NAT64 обязателен. Для связки двух IPv6-сетей через IPv4 — туннель проще и быстрее. И помните: NAT64 не решает проблему перехода. Он лишь откладывает её. Полный переход на IPv6 — единственное настоящее решение. Но это уже совсем другая история.Маршрут
DNS64 в BIND
Итоги