Возможности NAT в netfilter iptables

nat netfilter iptables

Настраивать проброс портов и общий доступ к интернету через один публичный адрес умеют все, но не все знают, что возможности NAT в netfilter гораздо шире. Сегодня я покажу вам эти возможности с помощью синтаксиса команды iptables.

Самые новые версии некоторых дистрибутивов уже используют nftables, но до ухода iptables в прошлое еще далеко. Поскольку популярные операционные маршрутизаторов, даже проприетарные, сейчас основаны на Linux, многое из данной статьи можно применить и к ним, при условии что их интерфейс не ограничивает формат опций искусственно, а просто передает их в правила iptables.

1:1 NAT

Все, кто использовал Amazon EC2, online.net и другие облачные платформы, наверняка с ним уже сталкивались. Публичные адреса для виртуалок настроить в админке можно, но самой виртуалке при этом выдается частный адрес.

Чтобы это сделать, нужно всего лишь указать по одному адресу вместо целой сети в --source/--destination и --to-destination/--to-source соответственно.

Вот команды для сопоставления частного адреса 10.0.0.10 публичному 102.0.2.10:

Если нет нужды подключаться к внутреннему адресу из интернета, достаточно одного правила SNAT — об ответах позаботится модуль conntrack, если он не выключен.

NETMAP

Что делать, если нужно транслировать не один адрес, а целую сеть? Нередко одной компании бывает нужно подключиться к сети другой — например, к поставщику технической поддержки или иных услуг. Проблемы начинаются, если у поставщика уже есть клиент с такой же сетью, как у вас.

В такой ситуации на помощь приходит опция NETMAP, которая транслирует одну сеть в другую.

Полезно знать, что сети для частного использования из RFC 1918 на самом деле очень большого размера. Вот они:

  • 10.0.0.0/8 (до 10.255.255.255.255);
  • 172.16.0.0/12 (до 172.31.255.255);
  • 192.168.0.0/16 (до 192.168.255.255).

Если выбрать менее популярные адреса, чем 192.168.(0|1).0 или 10.0.0.0, с конфликтом можно не столкнуться никогда.

Предположим, в компании-клиенте используется сеть 192.168.0.0/24, а в компании-поставщике — 10.85.0.0/24. Мы сделаем вид, что в нашей компании сеть не 192.168.0.0/24, а 172.17.18.0/24:

В отличие от SNAT и DNAT, она заменяет не весь адрес источника или назначения, а только адрес хоста — ту часть, где в маске сети нули. Адрес 192.168.0.10 всегда транслируется в 172.17.18.10, так что этот метод отлично подходит для двусторонней работы.

Если соединения инициируются только с внутренней или внешней стороны, здесь тоже можно обойтись без второго правила, достаточно настроить только PREROUTING для соединений снаружи или POSTROUTING для соединений изнутри, а остальное conntrack сделает за нас.

Очевидный недостаток — для правильной работы сети должны быть одинакового размера. Никакой проверки или даже требования предоставить опцию -s/-d в iptables нет. Если сеть источника меньше сети назначения, то вместе с адресом хоста NETMAP изменит и часть адреса сети. Если сеть источника больше — изуродует адрес хоста. Сетевой стек Linux вообще без предрассудков — делает ровно то, о чем его просят, даже если в этом нет никакого смысла.

Этот вид NAT также работает с IPv6:

NPT (Network Prefix Translation)

Более правильным решением для трансляции сетей IPv6 будет функция NPTv6, описанная в RFC 6296. Она не отслеживает соединения, так что ее производительность лучше, но потребуются два правила на вход и на выход:

NAT без conntrack

Подсистема отслеживания соединений (conntrack) решает много проблем и экономит время при настройке. Правила с опцией --state ESTABLISHED,RELATED есть почти у каждого пользователя iptables, без них пришлось бы писать два полных набора правил на вход и на выход. Кроме того, conntrack helpers (модули nf_nat_ftp и прочие) сильно упрощают работу с протоколами, которые требуют более одного соединения.

Обратная сторона удобства — меньшая производительность. В случае с NPTv6, да и с NETMAP и 1:1 NAT, если все равно указаны оба правила и опции никак не ограничивают протокол и порт, отслеживание состояний не приносит особой пользы и его можно было бы отключить.

Отключить отслеживание можно следующим образом:

Для IPv6 все так же, только с командой ip6tables.

С NOTRACK нужно быть очень осторожным. Если у вас есть правила с опцией --state, они, очевидно, перестанут работать, что может грозить потерей удаленного доступа к устройству. Убедитесь, что в правило попадет только трафик, который действительно не требует отслеживания состояний!

Балансировка трафика с помощью NAT

Классический masquerade транслирует множество внутренних адресов в один внешний. Если вывернуть это правило наизнанку, оно будет транслировать один внешний адрес во множество внутренних.

Это можно использовать для простой балансировки трафика. В отличие от nginx или varnish, балансировка на сетевом уровне ничего не знает о протоколе уровня приложений, но зато не зависит от конкретного протокола и работает с приложениями, для которых специализированных решений не существует.

Предположим, в нашей сети есть пять серверов с адресами 10.0.0.10–10.0.0.15 и мы хотим балансировать запросы к внешнему адресу 192.0.2.10 между ними. Это можно сделать следующей командой:

При включенном conntrack такая балансировка работает на уровне соединений, а не пакетов и вполне годится для протоколов, которые требуют постоянного соединения, вроде SSH или RDP. Единственный недостаток в том, что внутренние адреса серверов должны быть в непрерывном диапазоне. Никакого способа указать список адресов или сеть не предусмотрено.

С помощью дополнительных опций --random и --persistent можно повлиять на то, будет соединение с одного внешнего адреса с большей вероятностью отправлено на один и тот же внутренний адрес или нет.

Если поменять PREROUTING на POSTROUTING и -d на -s, можно транслировать один внутренний адрес во множество внешних. Я не знаю, кому и зачем это может потребоваться, но техническая возможность у вас есть.

Hairpin

Вы, возможно, уже сталкивались с ситуацией, когда с внешнего адреса маршрутизатора проброшен порт на сервер внутри сети, но при этом попасть на сервер по внешнему адресу изнутри сети не получается.

Правильное решение в этом случае — split horizon DNS. Многие серверы DNS, включая самый популярный BIND, умеют выдавать разный результат в зависимости от адреса клиента. Но в большинстве сетей нет своего сервера, и не всегда он нужен.

В этом случае приходит на помощь hairpin или NAT reflection. Предположим, у вас есть такое правило для проброса порта на веб-сервер:

Если из сети зайти на http://203.0.113.10, соединение отвалится с тайм-аутом. Если запустить tcpdump или tshark, можно увидеть, что на сервер пакеты приходят правильно. Проблема здесь в том, что, если вы отправляете запрос с 10.0.0.123, сервер посылает ответ не маршрутизатору, а напрямую обратно к 10.0.0.123, поскольку они в одной сети.

Остается одно: пропускать весь трафик из сети в нее саму через маршрутизатор:

NAT в ebtables

Обычно NAT ассоциируется с сетевым уровнем, но это не значит, что его нет на канальном. В кадрах Ethernet есть MAC-адреса источника и назначения, и ebtables позволяет их поменять.

К примеру, вам нужно перенаправить зеркалированный трафик с порта коммутатора в локальный процесс для анализа. Поменять IP-адрес назначения, чтобы пакеты попали в локальный процесс, можно с помощью iptables, но сначала нужно сделать так, чтобы MAC-адрес назначения совпадал с адресом сетевой карты, иначе ядро отбросит этот трафик, даже не посмотрев на IP.

Тут нам на помощь и придет ebtables:

Заключение

Не забывайте, что в недрах man iptables-extensions всегда можно отыскать что-то интересное. Не ограничивайтесь чужими статьями, читайте первоисточники сам и, если придумаете что-то интересное, не стесняйтесь предложить нам статью.

Понравилась статья? Поделиться с друзьями:
Добавить комментарий