NAT — как ваш домашний роутер прячет 50 устройств за одним IP
В вашем доме могут быть 30+ устройств с интернетом: ноутбук, телефон, планшет, умные лампочки, телевизор, робот-пылесос. У каждого свой IP-адрес вида 192.168.X.X. А ваш провайдер выдал вам один публичный IP. Как все они одновременно ходят в интернет, и сайты их различают?
Ответ: NAT (Network Address Translation). Ваш роутер переписывает заголовки уходящих пакетов так, что для внешнего мира они все выглядят как идущие от одного публичного IP. Когда ответ возвращается — роутер по своей таблице определяет, какому именно устройству он принадлежит.
В этом уроке разберём, как именно работает NAT, чем отличаются типы (full cone, restricted, symmetric), что такое port mapping, как работает hole punching для WebRTC и P2P-приложений. NAT — это hack, который спас IPv4 от смерти в 1990-х, но он усложнил многое: его особенности влияют на работу видеозвонков, файловых обменов, игровых серверов.
Bridge network и публикация портовЗачем NAT появился
К середине 1990-х стало ясно: IPv4-адресов не хватит на всех. Спроектировали IPv6 (1995), но внедрение шло медленно. Нужно было «дотянуть» IPv4. Решение — NAT.
Идея: вместо того, чтобы каждое устройство имело публичный IP, дать им приватные IP (10/8, 172.16/12, 192.168/16) и сделать один публичный IP на всю организацию. Роутер на границе переписывает заголовки пакетов.
Что NAT делает с пакетом:
- Уходящий пакет от ноутбука: src
192.168.1.42:54321, dst140.82.121.4:443. - NAT-роутер видит — src приватный, нужно переписать. Выбирает свой публичный src port (например,
61000). Запоминает в таблице:(внутр 192.168.1.42:54321) <-> (внеш 87.123.45.6:61000) -> (140.82.121.4:443). - Меняет src в пакете на
87.123.45.6:61000. Отправляет в интернет. - Сервер отвечает на
87.123.45.6:61000(свой src + dst NAT’a). - NAT-роутер видит пакет с dst
87.123.45.6:61000. По таблице узнаёт — это для192.168.1.42:54321. Переписывает dst, отправляет внутрь.
Это PAT (Port Address Translation) или NAPT (Network Address Port Translation) — по сути NAT, мультиплексирующий по портам. То что обычно называют просто «NAT» в домашних роутерах — именно PAT.
Типы NAT
Когда говорят о «типах NAT», обычно имеют в виду как роутер обращается с входящими пакетами. Это влияет на возможность принимать соединения извне (важно для VoIP, P2P, игр).
1. Full Cone NAT. Самый простой и открытый.
- Любой внешний хост может слать пакеты на
(публ IP, мапнутый порт). - NAT принимает и форвардит внутрь по таблице.
- Используется в старых домашних роутерах. Лучший для P2P.
2. Restricted Cone NAT.
- Внешний хост может слать только если внутренний хост уже что-то ему отправлял.
- Фильтрация по src IP внешнего хоста.
3. Port-Restricted Cone NAT.
- То же что Restricted, но проверяется и src port.
- Чуть более строгий.
4. Symmetric NAT. Самый строгий.
- Для каждого внешнего (dst IP, dst port) NAT использует разный внешний src port.
- Внешние хосты могут отвечать только на тот же IP:port, который они получили.
- Делает P2P и hole punching сложным — два узла не могут согласовать порт.
Современные домашние роутеры обычно делают что-то между Cone и Symmetric. Иногда называют «open NAT», «moderate NAT», «strict NAT» (в игровых консолях).
Узнать свой тип NAT можно через STUN-сервер (RFC 5389) или специальные онлайн-сервисы.
Port forwarding — проброс порта
Что если вы хотите запустить домашний сервер (Minecraft, домашняя камера, личный сайт)? Извне на ваш публичный IP никто не достучится — NAT не пропускает входящие соединения, для которых нет записи в таблице.
Решение — port forwarding: вручную прописать в NAT-таблице «входящие на public IP:8080 -> 192.168.1.100:80». Теперь когда кто-то снаружи стучится на 87.123.45.6:8080, NAT перенаправляет на ваш домашний сервер.
# Пример настройки на Linux (iptables):
iptables -t nat -A PREROUTING -p tcp --dport 8080 -j DNAT --to-destination 192.168.1.100:80
iptables -t nat -A POSTROUTING -p tcp -d 192.168.1.100 --dport 80 -j MASQUERADE
# В домашних роутерах есть UI -- Settings -> Port Forwarding:
# External port | Internal IP | Internal port | Protocol
# 8080 | 192.168.1.100 | 80 | TCP
Минусы:
- Нужно вручную настроить.
- Работает только если у вас публичный IP. Не работает за CGNAT (вы не можете «открыть» порт чужого NAT’a провайдера).
UPnP / NAT-PMP / PCP — автоматические протоколы, по которым приложение само просит роутер пробросить порт. Скайп, BitTorrent, игры используют это. Если в роутере включён UPnP, программы получают порты автоматически.
# Узнать, поддерживает ли роутер UPnP:
upnpc -l # покажет статус UPnP
# Пробросить порт через UPnP:
upnpc -a 192.168.1.100 80 8080 tcp
Hole punching — P2P через два NAT
Что если два устройства за разными NAT хотят соединиться напрямую (без сервера-посредника)? Например, видеозвонок WebRTC между A и B, оба дома.
Прямое соединение невозможно: ни A, ни B не могут принимать входящие connection’ы (NAT блокирует). Решение — NAT hole punching.
Алгоритм:
- A и B оба узнают свои публичные адреса через STUN-сервер.
- Через сигнальный сервер (отдельный) обмениваются этой информацией.
- Одновременно начинают слать пакеты друг другу. Первые пакеты дропаются NAT-ами (нет открытой записи). Но они открывают записи в своих NAT.
- После пары round-trips NAT уже разрешает пакеты в обе стороны.
Hole punching работает для UDP и часто для TCP (но сложнее). Лучше всего с full cone NAT. С symmetric NAT — не работает (порты разные для каждого target). В этом случае нужен TURN-сервер — сервер-relay, через который идёт весь трафик.
Это вся индустрия WebRTC: STUN + сигнальный сервер + TURN fallback. Zoom, Discord, Telegram-звонки — всё построено на этом.
CGNAT — NAT на уровне провайдера
CGNAT (Carrier-Grade NAT) — то же самое, но на уровне провайдера. Когда у провайдера тоже не хватает публичных IP, он ставит NAT на своей границе.
[Ваш дом] - [Дом-NAT] - [Провайдер-CGNAT] - [Интернет]
Внутри дома — ваш приватный IP (192.168.X.X). На вашем модеме — приватный IP провайдера (часто 100.64.X.X из RFC 6598). На выходе провайдера — их публичный IP.
Признак CGNAT:
# Узнать свой "публичный" IP с точки зрения интернета:
curl ifconfig.me
# 87.123.45.6
# Узнать IP вашего модема (на странице админки -- 192.168.1.1):
# Если IP модема НЕ совпадает с curl ifconfig.me -- значит CGNAT
# Если ваш модемный IP в 100.64.0.0/10 -- точно CGNAT
# Также можно посмотреть в traceroute -- первый хоп после вашего роутера будет
# в диапазоне 10/8 или 100.64/10 -- это NAT провайдера
Минусы CGNAT для пользователя:
- Нельзя пробросить порт. Хостить серверы из дома невозможно. Никакой UPnP не поможет.
- P2P-приложения хуже работают. Hole punching становится менее эффективным.
- Provider видит весь трафик. Точнее, NAT-логи провайдера показывают, кто и куда ходил.
- Множественные пользователи — один IP. Если кто-то с вашим IP заблокирован (например, забанен на форуме), банится все остальные.
В России CGNAT широко используется кабельными и особенно мобильными провайдерами. В США в основном Tier-3 операторы. Решение для активных пользователей — купить выделенный публичный IP (доплата 200-500 руб/мес).
Hairpinning / NAT loopback
Сценарий: у вас домашний сервер с port forward. Снаружи на 87.123.45.6:8080 все ходят нормально. А вы изнутри дома пытаетесь зайти на свой же сервер по публичному IP: curl http://87.123.45.6:8080. Работает? Часто нет.
Причина: пакет от вас идёт с приватного IP на публичный (свой же). Роутер видит «dst = мой публичный IP» — должен бы понять, что это его port forward, и отправить на 192.168.1.100. Но многие домашние роутеры этого не делают — называется отсутствие NAT hairpinning.
Решения:
- В админке роутера включить «NAT loopback» / «hairpin NAT» если есть такая опция.
- Использовать внутренний IP сервера (
192.168.1.100:80) изнутри дома. - Использовать split-DNS (внутри — внутренний IP, снаружи — публичный).
В корпоративных файрволах (pfSense, OPNsense) hairpinning обычно работает из коробки.
NAT и сложности с приложениями
Не все протоколы дружат с NAT. Известные проблемные:
1. FTP active mode. В active FTP клиент говорит «приходи ко мне на порт X для данных». Через NAT не работает — сервер не знает, как достучаться через NAT клиента. Решение — passive mode (клиент инициирует все соединения).
2. SIP (VoIP). SIP передаёт IP в заголовках сообщений. Через NAT IP в сообщении — приватный, ничего не работает. Решение — SIP ALG (Application Level Gateway) на роутере, который переписывает IP в заголовках. Но SIP ALG часто работает плохо — лучше отключить и использовать STUN.
3. IPsec. Шифрованные пакеты не позволяют NAT переписать headers TCP/UDP внутри. Решение — IPsec NAT-T (NAT Traversal) — инкапсулирует IPsec в UDP, который NAT уже может правильно обработать.
4. SCTP / DCCP. Многие NAT-устройства не понимают эти транспортные протоколы.
5. WebRTC. Работает, но требует STUN/TURN-инфраструктуры (см. выше).
NAT vs Firewall
NAT и firewall — разные вещи, хотя в практике совмещены:
- NAT — переписывает адреса/порты. По сути translation.
- Firewall — разрешает или дропает пакеты по правилам. По сути filtering.
NAT даёт побочный эффект firewall’а: входящие соединения, не инициированные изнутри, не имеют записи в NAT-таблице и дропаются. Это и есть «бесплатный firewall» в IPv4.
В IPv6, где NAT обычно нет, каждое устройство имеет публичный IP, и нужен явный firewall (не положиться на NAT). Это часто проблема — забывают настроить firewall в IPv6, и устройства торчат наружу.
# Просмотр NAT-таблицы Linux:
sudo iptables -t nat -L -n -v
# Просмотр текущих NAT-маппингов (conntrack):
sudo conntrack -L
# Показывает все активные соединения и их NAT-translation
Попробуй сам
# 1. Узнать ваш публичный IP:
curl ifconfig.me
# 2. Сравнить с локальным:
ip addr show # ваш приватный IP
# 3. Понять, есть ли CGNAT:
# - Откройте админку роутера, посмотрите его WAN IP
# - Сравните с curl ifconfig.me
# - Если разные -- между вами и интернетом ещё один NAT (CGNAT провайдера)
# 4. Посмотреть текущие NAT-translations (если у вас Linux-роутер):
sudo conntrack -L | head
# 5. Симулировать port forwarding:
# Запустить тестовый сервис локально:
python3 -m http.server 8000 --bind 192.168.1.42
# В админке роутера: External 8080 -> 192.168.1.42:8000
# Извне (например с телефона по 4G): curl http://YOUR_PUBLIC_IP:8080
# 6. Проверить, какой у вас тип NAT (через online STUN tester):
# https://test.webrtc.org/ -- покажет NAT type
# или приложение для STUN-теста
# 7. Посмотреть hairpin:
# Когда у вас есть port forward, попробуйте curl с публичного IP изнутри дома:
curl http://YOUR_PUBLIC_IP:8080
# Если работает -- роутер поддерживает hairpin. Если нет -- нужен внутренний IP.
# 8. На Linux-машине с NAT (например, гипервизор):
sudo iptables -t nat -L -n
# Увидите цепочки PREROUTING (входящий NAT -- port forward) и POSTROUTING (исходящий NAT -- masquerade)
# 9. Посмотреть, сколько NAT-сессий открыто:
cat /proc/net/nf_conntrack | wc -l # на современных Linux
# или
sudo conntrack -C