NAT у Linux: від трансляції адрес до iptables і nftables

⏱ 22 min read • TECH

Ноутбук має адресу 192.168.10.10, телефон — 192.168.10.20. Обидва одночасно відкривають той самий сайт, а сервер бачить запити з однієї зовнішньої IP-адреси. Як маршрутизатор розуміє, кому повернути кожну відповідь?

За цим стоїть NAT — Network Address Translation, трансляція мережевих адрес. У домашній мережі він дозволяє багатьом пристроям користуватися однією публічною IPv4-адресою. У Linux той самий механізм допомагає організувати вихід із приватної мережі, опублікувати внутрішній сервіс або узгодити адресацію між мережами.

Розберемо, що саме NAT змінює в пакеті, які задачі вирішує і як його налаштовувати. Практичні приклади використовують одну схему мережі, спочатку з iptables, потім із nftables. Для читання достатньо розуміти IP-адресу, підмережу, порт і шлюз; маски докладніше розглянуті в статті про IPv4.

Зміст

Навіщо виник NAT

IPv4 використовує 32-бітні адреси: теоретично це приблизно 4,29 мільярда комбінацій, частина яких має спеціальне призначення. Коли Інтернет почав зростати, стало зрозуміло, що видавати окрему глобально унікальну адресу кожному пристрою в такому просторі складно.

Один зі способів зменшити потребу в публічних адресах — повторно використовувати внутрішню адресацію в незалежних мережах. Два офіси можуть мати однакову мережу 192.168.10.0/24, доки ці адреси не потрібно безпосередньо маршрутизувати між ними.

У RFC 1631, опублікованому в травні 1994 року, NAT описували як тимчасове полегшення проблеми нестачі адрес. Його можна було впроваджувати на межі мережі, поступово, без заміни всіх кінцевих пристроїв.

Приватні адреси й публічний Інтернет

RFC 1918 визначає три блоки приватних IPv4-адрес:

БлокДіапазон
10.0.0.0/810.0.0.0–10.255.255.255
172.16.0.0/12172.16.0.0–172.31.255.255
192.168.0.0/16192.168.0.0–192.168.255.255

Ці адреси можна маршрутизувати всередині організації або через VPN, але вони не є глобально унікальними й не призначені для маршрутизації в публічному Інтернеті. Сервер в Інтернеті не має універсального маршруту до «вашого» 192.168.10.10, бо така адреса є в багатьох мережах.

NAT на межі підставляє адресу, придатну для зовнішнього обміну, а відповідь перетворює назад. Для спільного використання однієї адреси він зазвичай змінює також TCP- або UDP-порт.

Як NAT змінює пакет

Нехай клієнт 192.168.10.10 відкриває HTTPS-з’єднання до 198.51.100.20:443. Його операційна система вибрала локальний порт 51514. Зовнішня адреса шлюзу — 203.0.113.5.

До трансляції пакет має таку пару джерела й призначення:

192.168.10.10:51514 → 198.51.100.20:443

Шлюз створює відповідність і надсилає пакет назовні:

203.0.113.5:40001 → 198.51.100.20:443

У цьому прикладі змінилися адреса й порт джерела. Адреса сервера та порт 443 залишилися тими самими. Порт 40001 обраний для ілюстрації: NAT може зберегти початковий порт, якщо це дозволяють правила й немає конфлікту.

Інший клієнт може використати такий самий локальний порт 51514. Для звернення до того самого сервера шлюз призначить йому іншу зовнішню пару, наприклад 203.0.113.5:40002.

Два клієнти з однаковими локальними портами отримують різні зовнішні порти на NAT-шлюзі

Відповідь на перше з’єднання приходить так:

198.51.100.20:443 → 203.0.113.5:40001

За збереженим станом шлюз відновлює призначення:

198.51.100.20:443 → 192.168.10.10:51514

Описане перетворення адрес і портів називають NAPT — Network Address Port Translation, або PAT — Port Address Translation. Відмінність від трансляції лише адрес розглянута в RFC 3022.

Що зберігає conntrack

У Linux стан потоків відстежує підсистема connection tracking, або conntrack. Для TCP і UDP основа ідентифікації — протокол, адреси джерела й призначення та обидва порти. У складніших конфігураціях враховуються також контекст мережевого простору і conntrack-зона.

Тому запис NAT — не просто «порт 40001 належить ноутбуку». Це відповідність між напрямками конкретного потоку. TCP і UDP мають різні простори, а можливість повторного використання зовнішнього порту залежить від реалізації та адреси віддаленого вузла.

Conntrack відстежує і UDP, хоча в UDP немає встановлення з’єднання, як у TCP. Для нього стан існує за спостережуваними пакетами та таймерами. ICMP теж може проходити через NAT: там використовуються інші поля, зокрема ідентифікатор echo-запиту, а не TCP/UDP-порти.

NAT змінює пакети на шляху між кінцевими вузлами. Це не HTTP-проксі: зазвичай він не завершує TCP-сеанс і не розшифровує TLS. Під час зміни адрес або портів реалізація також коригує відповідні контрольні суми.

Типи NAT: різні осі класифікації

Назви NAT описують різні властивості. SNAT і DNAT відповідають на питання «яке поле змінюємо», static і dynamic — «як обираємо відповідність», NAT44 і NAT64 — «між якими сімействами адрес працюємо».

NAT44 означає трансляцію IPv4 в IPv4. Саме до неї належать звичні домашній SNAT і port forwarding. Позначення NAT444 часто використовують для схеми з домашнім і провайдерським NAT: три IPv4-адресні області та два рівні трансляції.

НазваЩо означаєПриклад
SNATЗміна адреси джерела, за потреби й портуLAN виходить через адресу шлюзу
DNATЗміна адреси призначення, за потреби й портуПублічний :8443 веде на внутрішній :443
Static NAT, 1:1Заздалегідь задана відповідність адресОкрема зовнішня адреса для внутрішнього сервера
Dynamic NATВибір зовнішньої адреси з пулуВнутрішні хости тимчасово використовують адреси пулу
NAPT / PATТрансляція адрес разом із портамиБагато клієнтів ділять одну IPv4-адресу
MasqueradingРізновид SNAT з адресою вихідного інтерфейсуВихід через WAN з динамічною адресою
REDIRECTПеренаправлення на локальний вузолДоставка трафіку локальному сервісу на іншому порту
Twice NATЗміна і джерела, і призначенняУзгодження мереж з адресами, що перетинаються

Статична відповідність не обов’язково означає відсутність стану: статичне правило DNAT у Linux зазвичай усе одно використовує conntrack. І навпаки, існують алгоритмічні stateless-перетворення, яким не потрібен окремий запис для кожного потоку.

Full cone, restricted і symmetric NAT

Ці назви часто зустрічаються в описах ігор, VoIP і P2P. Вони стосуються поведінки зовнішніх відповідностей та обмежень для вхідного трафіку.

Корисно розділяти два питання:

  • Mapping: чи зберігається зовнішня пара адреса–порт, коли один клієнт звертається до різних віддалених вузлів?
  • Filtering: від яких віддалених адрес і портів допускаються пакети до вже створеної відповідності?

RFC 4787 описує ці властивості окремо для UDP. Наприклад, endpoint-independent mapping не робить фільтрацію автоматично відкритою для всіх. Напис «symmetric NAT» або «NAT type 3» у програмі не дозволяє однозначно відновити набір правил iptables.

Що таке masquerading

Masquerading, або маскарадинг, — це SNAT, який бере адресу з вихідного інтерфейсу. Адміністратор вказує, який трафік транслювати, але не записує зовнішню адресу в самому правилі.

Порівняйте:

SNAT:        змінити джерело на 203.0.113.5
MASQUERADE:  використати адресу інтерфейсу, через який виходить пакет

Якщо провайдер видає WAN-адресу через DHCP або PPPoE, masquerading дозволяє не переписувати правило після зміни адреси. У Linux пов’язані masquerade-відповідності також видаляються при вимкненні інтерфейсу. Це не механізм збереження сеансів: після зміни зовнішньої адреси старе TCP-з’єднання зазвичай уже не може продовжитися.

Для постійної зовнішньої адреси зручно використовувати явний SNAT. Для динамічної — masquerading. Обидва виконують трансляцію джерела; masquerading не є окремим рівнем шифрування чи приховування трафіку. Семантика описана в документації MASQUERADE.

Які задачі NAT виконує зараз

Вихід приватних мереж назовні

Це типовий сценарій домашнього маршрутизатора, офісного шлюзу або NAT gateway: внутрішні пристрої відкривають з’єднання, а зовнішні системи бачать адресу шлюзу чи адреси його пулу. Організація може також використовувати цей пул як набір відомих вихідних адрес для партнерських allowlist.

Публікація внутрішніх сервісів

DNAT дозволяє доставити вхідний пакет до внутрішнього сервера. Наприклад, звернення до 203.0.113.5:8443 можна передати на 192.168.10.100:443.

Це трансляція TCP-порту. Вона не перетворює HTTP на HTTPS і не обирає сайт за доменом. Якщо за однією адресою потрібно розрізняти HTTP-hostname або завершувати TLS, потрібен відповідний reverse proxy чи балансувальник.

Контейнери, віртуальні машини та VPN

Хост може транслювати вихід із приватних мереж контейнерів або віртуальних машин. Публікація порту контейнера теж може використовувати DNAT. Конкретний шлях залежить від runtime, мережевого драйвера й режиму: rootless-мережа, kernel NAT та eBPF-рішення не є одним і тим самим механізмом.

Для VPN SNAT іноді використовують, коли віддалена мережа не має маршруту назад до клієнтського пулу. Це спрощує зворотний шлях, але приховує індивідуальні адреси клієнтів. Якщо можна додати коректні маршрути, трансляція може бути зайвою.

Перетин адресних просторів

Після об’єднання компаній дві мережі можуть використовувати однаковий 10.0.0.0/8 або однакові підмережі. Трансляція в інший, узгоджений адресний простір іноді дозволяє з’єднати їх до завершення перенумерації. Тут можуть знадобитися обидва напрямки перетворення, окремі routing domain і DNS-налаштування; одне правило masquerade не усуває неоднозначність усіх маршрутів.

Що залишається за firewall

NAT відповідає за перетворення адрес, firewall — за дозвіл або заборону трафіку. Вони часто працюють в одному пристрої й використовують спільний стан, але мають різні задачі.

Типовий домашній шлюз не приймає довільні нові вхідні з’єднання до клієнтів. Водночас статичний DNAT, автоматичне відображення порту чи інша політика можуть створити такий доступ. Перевіряти потрібно правила фільтрації, а не лише факт наявності NAT. Задачі локального захисту без трансляції також розглядає RFC 4864.

CGNAT і подвійний NAT

CGNAT — Carrier-Grade NAT — трансляція на стороні провайдера, де публічні IPv4-адреси ділять багато абонентів. Якщо домашній маршрутизатор теж виконує NAT, шлях може виглядати так:

Пристрій          Домашній шлюз        CGNAT провайдера      Інтернет
192.168.10.10  →  100.64.12.34      →  публічна IPv4      →  сервер

Блок 100.64.0.0/10, тобто 100.64.0.0–100.127.255.255, виділений як Shared Address Space у RFC 6598. Це не ще один приватний блок RFC 1918. Провайдерські мережі можуть використовувати й іншу внутрішню адресацію, тому наявність CGNAT не визначають лише за одним діапазоном.

Проброс порту на домашньому шлюзі налаштовує тільки ваш рівень трансляції. Якщо пакет з Інтернету не проходить CGNAT провайдера, домашнє правило його не отримає. Практичні варіанти — публічна IPv4 від провайдера, доступ через IPv6 за належної фільтрації або тунель до доступного ззовні вузла.

Зі спільною публічною адресою пов’язана й діагностика: для пошуку конкретного абонента одного IP недостатньо. Потрібні час, протокол, порт та журнали відповідностей.

Чому P2P потребує додаткових механізмів

Дві сторони за NAT не завжди можуть просто почати обмін на відомих приватних адресах. Для встановлення зв’язку використовують STUN, ICE, а за потреби — TURN-реле. STUN допомагає дізнатися зовнішню відповідність, ICE перевіряє можливі шляхи, TURN передає дані через проміжний сервер. Такий процес описаний у RFC 8445.

Працездатність залежить від mapping, filtering, таймерів і кількості рівнів трансляції. Відкритий TCP-порт на вашому шлюзі не гарантує працездатності іншого UDP-протоколу.

NAT у Linux: де змінюється пакет

Netfilter — механізми обробки пакетів у ядрі Linux. iptables і nftables — способи конфігурувати цю обробку з userspace. Команда nft не транслює кожен пакет сама: вона передає правила ядру.

Для пакета, який проходить через Linux-шлюз до іншого хоста, спрощений шлях такий:

Транзитний пакет: PREROUTING з DNAT, маршрутизація, FORWARD з фільтрацією, POSTROUTING зі SNAT

  • PREROUTING: DNAT може змінити призначення до вибору маршруту.
  • Маршрутизація: ядро визначає, куди передати пакет після цієї зміни.
  • FORWARD: правила фільтрації перевіряють транзитний пакет.
  • POSTROUTING: SNAT або masquerading змінює джерело перед виходом.

Отже, правило FORWARD для port forwarding зазвичай бачить уже внутрішню адресу й порт після DNAT. Для прикладу :8443 → 192.168.10.100:443 тут перевіряємо 192.168.10.100 і порт 443. Джерело на цьому етапі ще не змінене вихідним SNAT.

Пакети до самого шлюзу проходять через INPUT; створені локальним процесом — через OUTPUT. Тому запит, запущений на шлюзі, не є еквівалентом запиту зовнішнього клієнта до PREROUTING. Порядок hooks і пріоритетів наведений у документації Netfilter.

Правило обирає відповідність для потоку

У звичайному stateful NAT перший пакет потоку проходить пошук NAT-правила, яке створює відповідність. Наступні пакети й відповіді використовують її через conntrack. Окреме «зворотне правило» для відповіді не потрібне.

Це не означає, що наступні пакети минають маршрутизацію чи фільтрацію. Йдеться саме про повторний пошук NAT-відповідності. Через це лічильник NAT-правила не є лічильником усіх пакетів з’єднання, а зміна правила не переносить уже наявний потік на нову відповідність. Ця семантика описана в NAT-документації nftables.

Практика: одна мережа для всіх прикладів

Використаємо Linux-шлюз із двома інтерфейсами:

ЕлементЗначення
LAN-інтерфейс шлюзуeth1, адреса 192.168.10.1/24
WAN-інтерфейс шлюзуeth0, адреса 203.0.113.5
LAN192.168.10.0/24
Клієнт192.168.10.10, шлюз 192.168.10.1
Внутрішній HTTPS-сервер192.168.10.100:443, шлюз 192.168.10.1
Зовнішній порт для сервераTCP 8443

Адреси з 203.0.113.0/24, 198.51.100.0/24, 192.0.2.0/24 та IPv6 2001:db8::/32 у статті є документаційними прикладами. Для реальної мережі підставте видані вам адреси, назви інтерфейсів та маршрути.

Приклади нижче — два альтернативні варіанти для окремого навчального шлюзу без наявних правил фільтрації. Не застосовуйте обидва набори разом. На вузлі з Docker, firewalld, UFW або іншою системою керування потрібно інтегрувати правила в її конфігурацію: доданий раніше DROP чи інший base chain може змінити результат.

Увімкнути маршрутизацію

Для транзиту IPv4 між інтерфейсами потрібний forwarding:

sudo sysctl -w net.ipv4.ip_forward=1

Для збереження після перезавантаження додайте в /etc/sysctl.d/90-nat-gateway.conf:

net.ipv4.ip_forward = 1

І застосуйте цей файл:

sudo sysctl -p /etc/sysctl.d/90-nat-gateway.conf

Саме перемикання ip_forward може також скидати пов’язані IPv4-параметри до типових значень для хоста або маршрутизатора. Тому його задають до тонкого налаштування мережі; це зазначено в документації ядра.

На шлюзі має бути робочий маршрут назовні. На клієнтах і сервері — маршрут назад через цей шлюз. NAT не створює ці маршрути автоматично.

Традиційний підхід: iptables

У iptables трансляцію зазвичай налаштовують у таблиці nat, а дозвіл транзиту — у filter, ланцюжку FORWARD. Без -t команда використовує таблицю filter.

1. Вихід LAN через постійну адресу: SNAT

sudo iptables -t nat -A POSTROUTING \
  -s 192.168.10.0/24 -o eth0 \
  -j SNAT --to-source 203.0.113.5

Правило застосовується до трафіку з нашої LAN, що виходить через WAN. Інший напрямок, наприклад обмін усередині LAN, під нього не підпадає.

Для навчального шлюзу дозволимо вихід LAN і пакети стану ESTABLISHED,RELATED, решту транзиту відкинемо:

sudo iptables -A FORWARD \
  -m conntrack --ctstate INVALID -j DROP

sudo iptables -A FORWARD \
  -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

sudo iptables -A FORWARD \
  -i eth1 -o eth0 -s 192.168.10.0/24 \
  -m conntrack --ctstate NEW -j ACCEPT

sudo iptables -P FORWARD DROP

ESTABLISHED охоплює пакети потоку, для якого вже спостерігався обмін в обох напрямках. RELATED дозволяє пов’язані пакети, зокрема певні ICMP-повідомлення про помилки. Без них діагностика й Path MTU Discovery можуть працювати некоректно.

Цей приклад задає політику лише для транзиту. Захист сервісів самого шлюзу через INPUT налаштовується окремо. Довідник базового синтаксису — iptables(8).

2. Якщо WAN-адреса динамічна: MASQUERADE

Замість наведеного SNAT використайте:

sudo iptables -t nat -A POSTROUTING \
  -s 192.168.10.0/24 -o eth0 \
  -j MASQUERADE

Це альтернатива попередньому правилу трансляції. Додавати обидва для одного й того самого трафіку не потрібно: перша відповідна трансляція визначить результат.

3. Опублікувати сервер: DNAT

Передамо з’єднання до 203.0.113.5:8443 на 192.168.10.100:443:

sudo iptables -t nat -A PREROUTING \
  -i eth0 -d 203.0.113.5 -p tcp --dport 8443 \
  -j DNAT --to-destination 192.168.10.100:443

sudo iptables -A FORWARD \
  -i eth0 -o eth1 -p tcp \
  -d 192.168.10.100 --dport 443 \
  -m conntrack --ctstate NEW -j ACCEPT

Відповіді дозволяє вже створене правило ESTABLISHED,RELATED. Сервер має повертати їх через NAT-шлюз. Тоді conntrack автоматично перетворить джерело відповіді на 203.0.113.5:8443, яке очікує зовнішній клієнт.

Звичайний вхідний DNAT зберігає адресу клієнта на сервері. Додатковий SNAT у напрямку до сервера іноді спрощує маршрутизацію, але тоді сервер бачитиме адресу транслятора замість адреси клієнта.

4. Перегляд і збереження

sudo iptables -t nat -S
sudo iptables -t nat -L -n -v
sudo iptables -L FORWARD -n -v --line-numbers
sudo iptables-save > nat-gateway.v4

iptables-save записує поточні IPv4-правила у файл. Для відновлення:

sudo iptables-restore < nat-gateway.v4

Автоматичне завантаження після перезавантаження залежить від дистрибутива та його сервісів. Файл у поточному каталозі сам по собі не стає постійною конфігурацією. Відновлення також потрібно узгоджувати з іншими власниками правил.

Сучасний підхід: nftables

nftables дозволяє описати правила у структурованому файлі, використовувати набори й карти та застосовувати зміни транзакцією. При цьому логіка SNAT і DNAT залишається тією самою.

Є важлива відмінність у структурі: назви таблиць і ланцюжків довільні. Ланцюжок із назвою prerouting не почне отримувати пакети лише через назву. Його потрібно прив’язати до hook, вказати тип і пріоритет. Приклади прив’язки наведені в документації про chains.

Еквівалентна конфігурація шлюзу

Створіть nat-gateway.nft. Цей варіант поєднує SNAT, DNAT та фільтрацію з попереднього розділу:

table ip nat_demo {
    chain prerouting {
        type nat hook prerouting priority dstnat; policy accept;

        iifname "eth0" ip daddr 203.0.113.5 tcp dport 8443 counter dnat to 192.168.10.100:443
    }

    chain postrouting {
        type nat hook postrouting priority srcnat; policy accept;

        ip saddr 192.168.10.0/24 oifname "eth0" counter snat to 203.0.113.5
    }
}

table ip filter_demo {
    chain forward {
        type filter hook forward priority filter; policy drop;

        ct state invalid counter drop
        ct state established,related counter accept

        iifname "eth1" oifname "eth0" ip saddr 192.168.10.0/24 ct state new counter accept
        iifname "eth0" oifname "eth1" ip daddr 192.168.10.100 tcp dport 443 ct state new counter accept
    }
}

Ключові частини:

ЗаписЗначення
table ipПравила лише для IPv4
type natЛанцюжок трансляції зі stateful NAT-семантикою
priority dstnatПріоритет -100 для трансляції призначення
priority filterПріоритет 0 для фільтрації
priority srcnatПріоритет 100 для трансляції джерела
policy dropВідкинути транзит, який не дозволили правила ланцюжка
counterЗбирати лічильники для правила

В одному hook менше числове значення пріоритету виконується раніше. Це порядок обробників, а не «важливість» правила. Тип nat не призначений для загальної фільтрації всіх пакетів.

Перевірити та застосувати

Перший запуск передбачає, що таблиці nat_demo і filter_demo ще не існують:

sudo nft -c -f nat-gateway.nft
sudo nft -f nat-gateway.nft
sudo nft list ruleset

-c перевіряє допустимість команд без застосування змін, -f читає файл. Перевірка потребує відповідних прав і підтримки ядра; вона не доводить наявності маршруту чи доступності сервера.

Для подальшої заміни власних таблиць додайте на початок оновленого файла їх видалення перед повторним визначенням:

delete table ip nat_demo
delete table ip filter_demo

# Далі — повні визначення обох таблиць із нового файла.

Це варіант для оновлення, коли обидві таблиці вже існують. Видалення й нові визначення подаються одним файлом в одному nft -f, а не окремими командами між якими шлюз лишається без правил. Повторне виконання самого add rule додає дублікати; читання декларацій таблиць теж не слід вважати автоматичною повною заміною наявного набору.

Не потрібно очищати весь ruleset заради двох таблиць: там можуть бути правила інших сервісів. Також accept у вашому base chain не гарантує проходження через інші chains того самого hook — інший обробник ще може відкинути пакет. Деталі команд і вердиктів є в nft(8).

Для автоматичного запуску підключіть файл до конфігурації nftables, яку завантажує ваш дистрибутив. Якщо правилами керує firewalld або інша служба, використовуйте її механізм постійного налаштування.

Masquerading і сімейство inet

Для динамічної WAN-адреси замініть правило snat у postrouting на:

ip saddr 192.168.10.0/24 oifname "eth0" counter masquerade

Сімейство inet може містити правила для IPv4 та IPv6. Stateful NAT у ньому підтримується починаючи з Linux 5.2. Якщо адреса вказана явно, сімейство уточнюють у самій дії, наприклад:

ip saddr 192.168.10.0/24 oifname "eth0" snat ip to 203.0.113.5

Це приклад правила для postrouting типу nat у таблиці inet, а не додаткове правило до попереднього table ip. Один спільний файл для двох сімейств не означає, що IPv6 теж обов’язково потрібно транслювати.

Перехід з iptables

Спочатку перевірте backend:

iptables --version

Позначення nf_tables означає сумісний frontend iptables-nft: синтаксис iptables, backend nftables. Позначення legacy вказує на старий backend. Отже, назва команди сама по собі ще не говорить, який механізм використовується.

Для отримання еквівалентного синтаксису:

iptables-translate -t nat -A POSTROUTING \
  -s 192.168.10.0/24 -o eth0 -j MASQUERADE

sudo iptables-save > old-rules.v4
iptables-restore-translate -f old-rules.v4 > translated-rules.nft

Ці інструменти допомагають перекласти правила, але не вирішують питання власника конфігурації, порядку hooks і постійного завантаження. На сучасних ядрах різні NAT-backend можуть співіснувати, але кілька незалежних систем керування ускладнюють визначення того, яке правило створило відповідність. Про інструменти переходу — Moving from iptables to nftables.

Hairpin NAT: доступ до сервера зсередини LAN

Зовнішній клієнт уже відкриває 203.0.113.5:8443. Тепер ту саму адресу використовує ноутбук 192.168.10.10, хоча сервер 192.168.10.100 стоїть поруч у LAN. Це сценарій hairpin NAT, також відомий як NAT loopback або reflection.

Правило DNAT вище прив’язане до eth0, тому запит із eth1 під нього не потрапляє. Додаємо окреме правило для LAN. Але в нашій схемі цього недостатньо.

Якщо змінити лише призначення, сервер отримає пакет від 192.168.10.10. Ця адреса локальна для сервера, тому він відповість безпосередньо клієнту, оминаючи шлюз. Клієнт очікує відповідь від 203.0.113.5:8443, а отримає її від 192.168.10.100:443.

Для клієнта й сервера в одній підмережі типовим рішенням є додатковий SNAT на LAN-адресу шлюзу:

Клієнт надсилає:
192.168.10.10:51514 → 203.0.113.5:8443

Після DNAT і SNAT сервер отримує:
192.168.10.1:51514  → 192.168.10.100:443

Сервер відповідає шлюзу, який відновлює пару для клієнта:
203.0.113.5:8443   → 192.168.10.10:51514

Тут порт джерела показаний збереженим для простоти; за конфлікту він теж може змінитися.

До nftables-варіанта додаємо три правила:

sudo nft add rule ip nat_demo prerouting \
  iifname "eth1" ip saddr 192.168.10.0/24 \
  ip daddr 203.0.113.5 tcp dport 8443 \
  counter dnat to 192.168.10.100:443

sudo nft add rule ip nat_demo postrouting \
  iifname "eth1" oifname "eth1" \
  ip saddr 192.168.10.0/24 ip daddr 192.168.10.100 \
  tcp dport 443 ct status dnat \
  counter snat to 192.168.10.1

sudo nft add rule ip filter_demo forward \
  iifname "eth1" oifname "eth1" \
  ip saddr 192.168.10.0/24 ip daddr 192.168.10.100 \
  tcp dport 443 ct state new ct status dnat counter accept

ct status dnat звужує правила до потоків, які зазнали DNAT. Пакети у відповідь дозволяє наявне правило established,related. Для постійної конфігурації перенесіть ці правила у відповідні ланцюжки файла; окремі nft add rule самі цього не роблять.

Hairpin SNAT приховує справжню адресу LAN-клієнта від сервера. Альтернатива — split DNS: внутрішнім клієнтам ім’я сервісу повертає внутрішню адресу. При цьому номер порту DNS не змінює: якщо зовні використовується 8443, а всередині лише 443, потрібно окремо узгодити URL або порти слухання.

Чи є NAT в IPv6

Так, механізми трансляції для IPv6 існують. Але звичайний вихід IPv6-хоста в IPv6-Інтернет не потребує спільної адреси заради економії адресного простору. Типова схема — маршрутизований глобальний префікс і stateful firewall.

Глобальна адреса означає можливість маршрутизації, а не автоматичний дозвіл вхідних з’єднань. Політику доступу задає firewall. Розділення цих задач пояснюється в RFC 4864.

NAT66

NAT66 — загальна назва трансляції IPv6 в IPv6. Linux підтримує stateful IPv6 SNAT, DNAT і masquerading. Вони можуть бути потрібні через вимоги конкретної інфраструктури, але переносять у неї стан трансляції та пов’язані з ним операційні обмеження.

Наприклад, masquerade у postrouting типу nat таблиці ip6 технічно виконує IPv6-трансляцію. Наявність цієї можливості не робить її необхідною частиною кожної IPv6-мережі.

NPTv6: трансляція префіксів

NPTv6 — Network Prefix Translation for IPv6, описаний в експериментальному RFC 6296, задає алгоритмічну відповідність між внутрішніми й зовнішніми IPv6-адресами.

Він не ділить одну адресу між багатьма клієнтами через порти й не потребує стану для кожного потоку. Перетворення двобічне та checksum-neutral: зміна префікса компенсується в інших бітах адреси, щоб не переписувати контрольні суми транспортного рівня. Тому зводити його до довільного текстового «заміни перші символи адреси» некоректно.

Це інший механізм, ніж звичайний stateful masquerading. Окрему політику фільтрації потрібно визначати в обох випадках.

NAT64 і DNS64: IPv6-клієнт звертається до IPv4-сервера

Інша задача виникає, коли клієнт має лише IPv6-зв’язність, а потрібний сервер — лише IPv4. NAT64 переводить пакети між сімействами адрес; це вже не просто заміна адреси в IPv4-заголовку.

У типовому stateful-сценарії NAT64 має IPv4-адресу або пул для звернень до серверів. IPv6-клієнт використовує спеціальну IPv6-адресу призначення, що представляє IPv4-сервер. Поведінка описана в RFC 6146.

DNS64 синтезує IPv6-адресу для IPv4-сервера, а NAT64 перетворює пакети між IPv6 та IPv4

Наприклад, IPv4-адресу 192.0.2.80 з well-known prefix 64:ff9b::/96 можна представити як 64:ff9b::c000:250. Частина c000:0250 — це байти 192.0.2.80 у шістнадцятковому записі. У конкретній мережі може використовуватися інший префікс трансляції.

DNS64 допомагає клієнту знайти таку адресу: коли відповідного AAAA-запису немає, резолвер може синтезувати його з A-запису та налаштованого префікса. DNS64 працює з DNS-відповідями, NAT64 — з пакетами. Це окремі функції; деталі синтезу наведені в RFC 6147.

Застосунок з жорстко заданою IPv4-адресою або лише IPv4 API не стає IPv6-сумісним від появи DNS64. Для таких сценаріїв існує 464XLAT: локальна stateless-трансляція CLAT працює разом зі stateful NAT64 на стороні мережі. Архітектуру описує RFC 6877.

Звичайні правила snat або masquerade в nftables не створюють NAT64-шлюз. Для нього потрібна реалізація міжсімейної трансляції, маршрути до префікса й узгоджене DNS-налаштування.

Як перевіряти та діагностувати NAT

Перевіряйте шлях поетапно: адреси й маршрути, forwarding, вибір NAT-відповідності, фільтрацію, доставку до сервісу та повернення відповіді.

1. Адреси, маршрути та forwarding

ip -br address
ip route
ip route get 198.51.100.20
sysctl net.ipv4.ip_forward

ip route get показує вибір маршруту в заданому контексті; простий виклик на шлюзі не відтворює всі параметри транзитного пакета, наприклад вхідний інтерфейс або policy-routing mark.

На сервері перевірте слухання порту:

ss -lntp 'sport = :443'

Перевірку зовнішнього port forwarding виконуйте з окремого зовнішнього вузла:

nc -vz 203.0.113.5 8443

Успіх означає можливість TCP-з’єднання, але ще не коректність TLS-сертифіката чи самого застосунку. Для перевірки HTTP/TLS потрібен окремий запит із правильним hostname.

2. Подивитися правила й лічильники

sudo nft -a list table ip nat_demo
sudo nft -a list table ip filter_demo

Для iptables-варіанта:

sudo iptables -t nat -L -n -v
sudo iptables -L FORWARD -n -v

Якщо правило має нульовий лічильник, перевірте інтерфейс, адресу, протокол, порт і порядок правил. Для NAT також важливо почати новий потік: вже відоме з’єднання не зобов’язане знову пройти пошук NAT-правила.

3. Подивитися conntrack

Утиліта conntrack постачається в пакеті conntrack-tools або conntrack, залежно від дистрибутива:

sudo conntrack -L -p tcp
sudo conntrack -E -p tcp

-L показує записи, -E — потік подій. У записі є кортежі original і reply: зіставлення цих напрямків дозволяє побачити трансляцію. Можливості інструмента описані на сторінці conntrack-tools.

Після зміни NAT-правила для перевірки достатньо створити нове з’єднання з новим кортежем. Не потрібно очищати всю таблицю станів: це зачепить інші потоки. Видалення самого правила теж не гарантує негайного завершення вже встановлених з’єднань; для блокування змінюють політику фільтрації та, за потреби, конкретний стан.

4. Порівняти трафік із двох боків

Для вихідного з’єднання до нашого демонстраційного HTTPS-сервера:

sudo tcpdump -ni eth1 'host 198.51.100.20 and tcp port 443'
sudo tcpdump -ni eth0 'host 198.51.100.20 and tcp port 443'

На LAN очікуємо джерело 192.168.10.10, на WAN — 203.0.113.5. Для вхідного port forwarding на WAN бачимо порт 8443, на LAN до внутрішнього сервера — 443.

5. Трасувати правила nftables

Для короткої діагностики можна позначити вузько вибраний потік для трасування. Приклад нижче передбачає, що тимчасової таблиці nat_trace ще немає:

sudo nft add table ip nat_trace
sudo nft 'add chain ip nat_trace prerouting { type filter hook prerouting priority -301; policy accept; }'
sudo nft add rule ip nat_trace prerouting \
  iifname "eth1" ip saddr 192.168.10.10 \
  ip daddr 198.51.100.20 tcp dport 443 meta nftrace set 1

sudo nft monitor trace

Створіть тестове з’єднання з клієнта в іншому терміналі. Після завершення зупиніть monitor і видаліть лише тимчасову таблицю:

sudo nft delete table ip nat_trace

nft monitor trace сам по собі не вмикає трасування кожного пакета: потрібен nftrace. Докладніше — Ruleset debug/tracing.

Типові симптоми

СимптомЩо перевірити
Пакет не доходить до шлюзуАдресу, маску, gateway, VLAN, ARP
На WAN видно приватне джерелоУмови SNAT, вихідний інтерфейс, старий conntrack-запис
DNAT спрацював, сервер не отримав пакетМаршрут після DNAT, FORWARD, firewall сервера
Сервер отримує запит, клієнт чекаєЗворотний маршрут через NAT, асиметрію, фільтрацію відповіді
Зовні працює, з LAN за публічною адресою — ніLAN-DNAT, hairpin SNAT або split DNS
Після правки правила результат старийЧи тестується вже встановлений потік
Домашній port forwarding не отримує запитиCGNAT, ще один маршрутизатор, upstream-фільтрацію
Дрібні запити працюють, передача зависаєMTU, ICMP-помилки, VPN-тунель і Path MTU Discovery

Межі stateful NAT

NAT-шлюз має скінченні ресурси: порти, пам’ять для станів і продуктивність. Одна публічна адреса не означає гарантовані «рівно 65 тисяч з’єднань»: місткість залежить від протоколу, віддалених адрес, портової політики й таймерів.

У Linux кількість записів і налаштований максимум можна подивитися так:

sysctl net.netfilter.nf_conntrack_count
sysctl net.netfilter.nf_conntrack_max

Значення та параметри таймерів описані в документації conntrack sysctl. Збільшувати максимум варто після оцінки пам’яті й причин накопичення станів.

Інший наслідок — залежність від зворотного шляху. Якщо відповідь прийшла на вузол без потрібної відповідності, він не зможе виконати зворотну трансляцію. Відмовостійкий stateful NAT потребує узгодженого шляху та, за відповідної архітектури, синхронізації стану.

Протоколи, які передають адреси всередині payload, можуть потребувати окремого NAT traversal або helpers. Універсальне переписування вмісту непридатне для довільного зашифрованого трафіку: для кожного протоколу потрібно розуміти його модель обміну.

Шпаргалка вибору

ЗадачаЩо використовувати
LAN виходить через постійну IPv4SNAT і дозвіл транзиту
WAN-адреса змінюєтьсяMasquerading і дозвіл транзиту
Опублікувати внутрішній TCP/UDP-сервісDNAT, FORWARD, коректний зворотний маршрут
Передати трафік сервісу на самому шлюзіREDIRECT або локальний DNAT, відповідна локальна фільтрація
LAN-клієнт використовує зовнішню адресу LAN-сервераHairpin NAT або узгоджений split DNS
Приватні мережі вже мають маршрути одна до одноїЗвичайна маршрутизація; NAT може не знадобитися
IPv6-хости звертаються до IPv6-ІнтернетуМаршрутизація й firewall
IPv6-only клієнти звертаються до IPv4-сервісівNAT64, зазвичай разом із DNS64
Потрібна stateless-трансляція IPv6-префіксівОцінити NPTv6 та його обмеження

Для будь-якої схеми NAT корисно виписати чотири речі: початкову пару адрес і портів, пару після трансляції, правило фільтрації та шлях відповіді. Це дозволяє перевірити конфігурацію незалежно від того, записана вона через iptables, nftables чи інструмент керування маршрутизатором.

Comments

© 2025 CodeByMe.de | Engineering