Частные сети и NAT

TL;DR: Частные (private) адреса (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16) не маршрутизируются в интернете — они для внутренних сетей. NAT (Network Address Translation) подменяет частные адреса на публичный при выходе в интернет. В Linux NAT реализуется через netfilter (iptables/nftables) и называется «маскарадинг» — все внутренние хосты выходят в интернет через один публичный IP.

Проблема: IPv4-адресов не хватает

IPv4 имеет ~4.3 миллиарда адресов (32 бита). Устройств в мире — десятки миллиардов. Решение — разделить адреса на публичные (маршрутизируемые в интернете) и частные (для внутренних сетей), а между ними поставить NAT.

Частные адреса (RFC 1918)

Три диапазона зарезервированы для частных сетей. Маршрутизаторы в интернете не передают пакеты с такими адресами — они существуют только внутри локальных сетей.

ДиапазонCIDRКол-во адресовТипичное применение
10.0.0.010.255.255.25510.0.0.0/816 777 216Облачные VPC (AWS, GCP), корпоративные сети
172.16.0.0172.31.255.255172.16.0.0/121 048 576Docker (172.17.0.0/16), Kubernetes Pod CIDR
192.168.0.0192.168.255.255192.168.0.0/1665 536Домашние и офисные сети

Один и тот же частный адрес 192.168.1.100 может использоваться в миллионах разных сетей одновременно — они изолированы и не знают друг о друге.

Другие специальные диапазоны

ДиапазонНазначение
127.0.0.0/8Loopback (localhost)
169.254.0.0/16Link-local (APIPA — автоназначение, когда DHCP недоступен)
100.64.0.0/10Carrier-Grade NAT (ISP-уровень)

Что такое NAT

NAT (Network Address Translation) — подмена адресов в заголовках пакетов при прохождении через маршрутизатор. Позволяет множеству хостов с частными адресами выходить в интернет через один публичный IP.

Как работает NAT (SNAT/Masquerade)

Внутренняя сеть                NAT-маршрутизатор              Интернет
192.168.1.0/24                 192.168.1.1 (внутр.)
                               203.0.113.5 (публ.)

Хост A (192.168.1.100)
  │
  │ Пакет: src=192.168.1.100:49832  dst=93.184.216.34:443
  │
  ▼
NAT-маршрутизатор:
  1. Запоминает: {192.168.1.100:49832 ↔ 203.0.113.5:61234}
  2. Подменяет src: 192.168.1.100:49832 → 203.0.113.5:61234
  │
  │ Пакет: src=203.0.113.5:61234  dst=93.184.216.34:443
  │
  ▼
Сервер (93.184.216.34) отвечает:
  │
  │ Пакет: src=93.184.216.34:443  dst=203.0.113.5:61234
  │
  ▼
NAT-маршрутизатор:
  3. Находит запись: {203.0.113.5:61234 ↔ 192.168.1.100:49832}
  4. Подменяет dst: 203.0.113.5:61234 → 192.168.1.100:49832
  │
  │ Пакет: src=93.184.216.34:443  dst=192.168.1.100:49832
  │
  ▼
Хост A получает ответ

NAT-маршрутизатор ведёт таблицу трансляций (connection tracking) — для каждого активного соединения помнит соответствие внутренний:порт ↔ внешний:порт.

Типы NAT

ТипНаправлениеЧто подменяетсяПрименение
SNAT (Source NAT)Изнутри → наружуSource IPВыход в интернет
MasqueradeИзнутри → наружуSource IP (автоматически берёт IP интерфейса)Выход в интернет (динамический IP)
DNAT (Destination NAT)Снаружи → внутрьDestination IP + портPort forwarding, проброс портов

SNAT и Masquerade делают одно и то же — подменяют source IP. Разница: SNAT требует явно указать публичный IP (--to-source 203.0.113.5), Masquerade автоматически берёт текущий IP выходного интерфейса. Masquerade чуть медленнее (смотрит IP каждый раз), но работает при динамическом IP (DHCP от провайдера).

Port Forwarding (DNAT)

Обратная задача: сделать внутренний сервер доступным извне.

Интернет → 203.0.113.5:8080 → NAT(DNAT) → 192.168.1.50:80

Запрос из интернета на публичный IP:8080 перенаправляется
на внутренний веб-сервер 192.168.1.50:80

NAT в Linux (netfilter)

Linux реализует NAT через подсистему ядра netfilter. Утилиты: iptables (legacy) или nftables (современный).

Masquerade (выход в интернет)

# Включить forwarding (пропуск пакетов между интерфейсами)
sudo sysctl -w net.ipv4.ip_forward=1
 
# iptables: маскарадинг для всех из 192.168.1.0/24
sudo iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth0 -j MASQUERADE
 
# nftables: эквивалент
sudo nft add table nat
sudo nft add chain nat postrouting { type nat hook postrouting priority 100 \; }
sudo nft add rule nat postrouting oifname "eth0" ip saddr 192.168.1.0/24 masquerade

Port Forwarding (DNAT)

# iptables: входящий трафик на :8080 → внутренний сервер 192.168.1.50:80
sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 8080 -j DNAT --to-destination 192.168.1.50:80
sudo iptables -A FORWARD -p tcp -d 192.168.1.50 --dport 80 -j ACCEPT
 
# nftables: эквивалент
sudo nft add chain nat prerouting { type nat hook prerouting priority -100 \; }
sudo nft add rule nat prerouting iifname "eth0" tcp dport 8080 dnat to 192.168.1.50:80

Connection Tracking

Ядро отслеживает состояние NAT-соединений:

# Текущие NAT-трансляции
sudo conntrack -L
# tcp  6 117 TIME_WAIT src=192.168.1.100 dst=93.184.216.34 sport=49832 dport=443
#   src=93.184.216.34 dst=203.0.113.5 sport=443 dport=61234 [ASSURED]
 
# Количество отслеживаемых соединений
cat /proc/sys/net/netfilter/nf_conntrack_count
cat /proc/sys/net/netfilter/nf_conntrack_max

NAT в Docker и Kubernetes

Docker и Kubernetes активно используют NAT:

Docker: контейнер получает IP из 172.17.0.0/16. При выходе в интернет — masquerade через хост. При -p 8080:80 — DNAT с хоста в контейнер.

# Docker добавляет правила автоматически
sudo iptables -t nat -L -n | grep DOCKER
# MASQUERADE  all  --  172.17.0.0/16  0.0.0.0/0
# DNAT       tcp  --  0.0.0.0/0      0.0.0.0/0   tcp dpt:8080 to:172.17.0.2:80

Kubernetes: Service типа ClusterIP использует DNAT (через kube-proxy / iptables) для маршрутизации к Pod-ам. NodePort — DNAT с внешнего порта ноды на Pod.

Недостатки NAT

НедостатокОписание
Нарушает end-to-endВнешний хост не может инициировать соединение к внутреннему (без port forwarding)
Усложняет протоколыFTP, SIP, IPsec требуют специальной обработки (ALG)
СостояниеNAT-маршрутизатор хранит таблицу трансляций — это ресурсы и точка отказа
Маскирует проблемыОтладка сетевых проблем сложнее — адреса подменены

IPv6 спроектирован так, чтобы NAT был не нужен — адресов хватает на каждое устройство. На практике NAT для IPv4 будет жить ещё долго.

Подводные камни

ПроблемаСимптомРешение
Нет интернета за NATping 8.8.8.8 с внутреннего хоста не работаетПроверить: ip_forward=1? MASQUERADE-правило есть? iptables -t nat -L
Port forwarding не работаетВнешний клиент не достучитсяПроверить DNAT-правило + FORWARD-правило (оба нужны)
conntrack table fullnf_conntrack: table full, dropping packet в dmesgУвеличить nf_conntrack_max или уменьшить таймауты
Docker-контейнер не доступен извнеПорт не проброшен-p 8080:80 при запуске, или docker-compose ports:
Hairpin NAT не работаетВнутренний хост не может обратиться к port forwarding по внешнему IPДобавить DNAT для трафика из внутренней сети + MASQUERADE/SNAT

Связанные материалы

  • networking — стек TCP/IP, IP-адреса, подсети, маршрутизация
  • dhcp — автоматическое назначение IP в локальной сети
  • linux-router — настройка Linux как маршрутизатора
  • configure-firewall — ufw, iptables/nftables