Обзор и сравнение способов настройки NAT на FreeBSD

В этой статье я бы хотел привести примеры настройки NAT на ОС FreeBSD и провести некоторое сравнение способов, которые, по моему мнению, наиболее часто используются.

Для начала:
NAT (от англ. Network Address Translation — «преобразование сетевых адресов») — это механизм в сетях TCP/IP, позволяющий преобразовывать IP-адреса транзитных пакетов. Также имеет названия IP Masquerading, Network Masquerading и Native Address Translation.

Рассмотренные варианты:
— Демон Natd
— IPFilter (ipnat)
— PF nat
— ng_nat
— ipfw nat (kernel nat)


NAT с помощью natd

Из хендбука:
Демон преобразования сетевых адресов (Network Address Translation) во FreeBSD, широко известный как natd(8), является демоном, который принимает входящие IP-пакеты, изменяет адрес отправителя на адрес локальной машины и повторно отправляет эти пакеты в потоке исходящих пакетов. natd делает это, меняя IP-адрес отправителя и порт таким образом, что когда данные принимаются обратно, он может определить расположение источника начальных данных и переслать их машине, которая запрашивала данные изначально.

Для работы natd нужен ipfw.
В ядре:
#Поддержка ipfw
options IPFIREWALL
options IPFIREWALL_VERBOSE
options «IPFIREWALL_VERBOSE_LIMIT=100»
#DIVERT пакетов приходящих на интерфейс для NAT
options IPDIVERT

В /etc/rc.conf добавить
gateway_enable=«yes»
или в /etc/sysctl.conf добавить
net.inet.ip.forwarding=1.

em0 – внешний интерфейс
192.168.0.0/24 – внутренняя сеть
200.200.200.200 – внешний адрес

Также в /etc/rc.conf добавить:
natd_enable=«YES»
natd_interface=«em0»
natd_flags=""

В фаервол добавляем правила для divert:
/sbin/ipfw add divert natd ip from 192.168.0.0/24 to any out via em0
/sbin/ipfw add divert natd ip from any to 200.200.200.200 in via em0

Более подробно описано в Хендбуке.

NAT с помощью IPFilter (ipnat)

В ядре:
options IPFILTER
options IPFILTER_LOG
или подгрузить как модуль и не трогать ядро.

В /etc/rc.conf добавить
gateway_enable=«yes»
или в /etc/sysctl.conf добавить
net.inet.ip.forwarding=1.

Также в /etc/rc.conf добавить:
ipnat_enable=«YES» #Включаем ipnat
ipnat_program="/sbin/ipnat" #Путь к ipnat
ipnat_rules="/etc/ipnat.rules" #Правила
ipnat_flags="" #С какими параметрами стартовать

Для ведения логов в syslog.conf добавить:
local0.* /var/log/ipmon.log
и запустить утилиту мониторинга работы IPFilter — ipmon с ключами -Dvas
-D – запуститься демоном
-v – детализировать
-a – отслеживать все устройства IPFilter
-s – через syslog

Примеры:

Если:
em0 – внешний интерфейс
192.168.0.0/24 – внутренняя сеть
200.200.200.200 – внешний адрес

То пример правил для Нат будет выглядеть так:
map em0 from 192.168.0.0/24 to any -> 200.200.200.200/32

Или без конкретизации адресов назначения:
map em0 192.168.0.0/24 -> 200.200.200.200/32

Если адрес динамический то можно сделать так:
map em0 192.168.0.0/24 -> 0.0.0.0/32

Некоторые полезные команды при работе с ipnat:
Перезагрузка ipnat:
/etc/rc.d/ipnat restart
Общая статистика роботы Нат:
ipnat –s
Список активных правил и список активных в данный момент сеансов:
ipnat –l
Перечитать конфиг:
ipnat -CF -f /etc/ipnat.rules
-C — очищает таблицу правил.
-F — удаляет записи из таблицы трансляций.
Больше об ipnat и IPFilter в целом можно узнать из:
ipnat(1), ipnat(5), ipnat(8), ipf(5), ipf(8), ipfstat(8), ipftest(1), ipmon(8)
Более подробно здесь.

NAT с помощью pf

В ядре:
device pf # Включаем PF OpenBSD packet-filter firewall
device pflog # Поддержка логов pf

В /etc/rc.conf добавить
gateway_enable=«yes»
или в /etc/sysctl.conf добавить
net.inet.ip.forwarding=1.

Также в /etc/rc.conf добавить:
pf_enable=«YES»
pf_rules="/etc/pf.conf"
pf_program="/sbin/pfctl"
pf_flags=""
pflog_enable=«YES»
pflog_logfile="/var/log/pf.log"
pflog_program="/sbin/pflogd"
pflog_flags=""

Пример самого правила:
em0 – внешний интерфейс
192.168.0.0/24 – внутренняя сеть
200.200.200.200 – внешний адрес

В /etc/pf.conf:
nat on em0 from 192.168.0.0/24 to any -> (em0)

NAT с помощью ng_nat

В ядре:
options NETGRAPH
options NETGRAPH_IPFW
options LIBALIAS
options NETGRAPH_NAT
…и другие опции нетграфа если надо

Или просто подгрузить модули:
/sbin/kldload /boot/kernel/ng_ipfw.ko
/sbin/kldload /boot/kernel/ng_nat.ko

em0 – внешний интерфейс
192.168.0.0/24 – внутренняя сеть
200.200.200.200 – внешний адрес

Создание НАТ ноды:
ngctl mkpeer ipfw: nat 60 out
ngctl name ipfw:60 nat
ngctl connect ipfw: nat: 61 in
ngctl msg nat: setaliasaddr 200.200.200.200
В ipfw добавляем строчки для перенаправления трафика в созданную ноду:
/sbin/ipfw add netgraph 61 all from any to 200.200.200.200 in via em0
/sbin/ipfw add netgraph 60 all from 192.168.0.0/24 to any out via em0
далее
sysctl net.inet.ip.fw.one_pass=0

Все написанное оформить виде скрипта и засунуть в /usr/local/etc/rc.d с правами запуска для автозагрузки.

Более подробно здесь.

NAT с помощью ipfw nat

Поддержка ipfw nat появилась начиная с версии FreeBSD 7.0
В ядро:
options IPFIREWALL
options IPFIREWALL_DEFAULT_TO_ACCEPT
options IPFIREWALL_FORWARD
options IPFIREWALL_VERBOSE
options IPFIREWALL_VERBOSE_LIMIT=50
options IPFIREWALL_NAT
options LIBALIAS

В /etc/rc.conf добавляем
firewall_enable=«YES»
firewall_nat_enable=«YES»
firewall_type="/etc/firewall"
gateway_enable=«YES»

В /etc/sysctl.conf добавить:
net.inet.ip.fw.one_pass=1

em0 – внешний интерфейс
192.168.0.0/24 – внутренняя сеть
200.200.200.200 – внешний адрес

Пример:

/sbin/ipfw add nat 1 config log if em0 reset same_ports
/sbin/ipfw add nat 1 ip from 192.168.0.0/24 to not table\(10\) via em0
/sbin/ipfw add nat 1 ip from any to 200.200.200.200 via em0
Где table 10 – не идет через нат

Некоторую статистику можно посмотреть так:
ipfw nat 1 show

Немного сравнения

Следует сказать, что ipfw, natd, ipf, ipnat отлично уживаются вместе. При этом нужно помнить особенности фильтров: ipfw срабатывает по первому совпадению, а ipf (без опции quick в правиле) – по последнему. Ну и всегда следует иметь в виду порядок прохождения пакета через фильтры. Так, если поддержка ipf собрана в ядре, то независимо от того, как запущен ipfw, в первую очередь пакеты будут проходить через правила ipf, а ipfw получит на вход только то, что будет им пропущено. Если же ipfw собран в ядре, а ipf подгружен как модуль, то правом первенства будет пользоваться ipfw.

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

Natd:
Подыхает становится не эффективен, когда трафик превышает 40-50 мегабит
— Реализация в виде демона
— Сложности при работе на нескольких интерфейсах
+ Простота настройки
+ Функциональность, гибкость

IPnat:
+ Простота настройки
+ «близость» к ядру
— При очень больших нагрузках нужен тюнинг


ng_nat:
— Сравнительно сложная настройка
— Не умеет redirect_port
+ Реализирован через libalias в ядре
+ Потребляет сравнительно немного ресурсов

Ipfw nat:
+ Скорость работы
+ Гибкость
+ Реализирован через libalias в ядре
UPD от nightfly:
— невозможность нормально без тонны алиасов натить из под пула
— невнятная статистика
+ наконец перестало течь
+ в отличии от иных умеет активное фтп изкоробки что позволяет не держать рядом фтп прокси
+ не страдает детскими болезнями типа приколов с одновременными pptp сквозь нат

Pf nat:
+ Скорость работы
+ Использование макросов для написания правил
— Проблемы с smp

Выводы

Я не буду отмечать никакой из выше описанных вариантов ввиду того, что тема немного холиварная, и мнения читателей могут не совпадать с моим. Я только попытался описать примеры настройки и сделать некоторое сравнение множества методов организации NAT на ОС FreeBSD. Также я не стал описывать матчасть по NAT, потому, что она есть здесь.
AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 35

    +3
    Просто, доступно, ничего лишнего. Отличная статья. В избранное однозначно!
      +2
      Интересная статья, познавательно, спасибо.
        +5
        Вот именно таких материалов хабру и не хватает.

        Добро пожаловать на Хабр :)
          +4
          Спасибо! Буду стараться на благо сообщества.
            +1
            Поправочка, на благо Хабра!
              +1
              Что, в общем-то, одно и то же :)
                +1
                Сообщество… как-то неопределенно, вы ведь простите это математику? :)
                Просто Хабр… ну Хабр — это Хабр, его ни с чем не спутаешь.
                  0
                  «Просто Хабр… ну Хабр — это Хабр»

                  «вы ведь простите это математику? :)»

                  Я должен был догадаться сразу! :)
            0
            вы еще плюсоминусы ipfw nat забыли записать:
            — невозможность нормально без тонны алиасов натить из под пула
            — невнятная статистика
            + наконец перестало течь
            + в отличии от иных умеет активное фтп изкоробки что позволяет не держать рядом фтп прокси
            + не страдает детскими болезнями типа приколов с одновременными pptp сквозь нат

            ЗЫ сам его и использую

              0
              Это плюсы libalias, а не собственно ipfw nat`а.
                0
                Спасибо. Добавил Ваши поправки в статью.
                  0
                  Кстати как почистить все правила ната?
                  типа как с чисткой таблиц, правил и очередей?

                  ${fwcmd} -f flush
                  ${fwcmd} -f pipe flush
                  ${fwcmd} -f queue flush
                  ${fwcmd} -f table 1 flush
                  ${fwcmd} -f table 2 flush
                  0
                  Странная настройка ipfw nat, у меня ядерный нат так работал:
                  ipfw nat 1 config redirect_addr some_nat_ip some_local_ip \
                  redirect_addr some_nat_ip some_local_ip
                  ipfw table 30 add some_nat_ip
                  ipfw table 30 add some_nat_ip
                  ipfw table 40 add some_local_ip
                  ipfw table 40 add some_local_ip
                  ipfw add 1 nat 1 ip from any to table\(40\)
                  ipfw add 2 nat 1 ip from table\(30\) to any
                  ipfw add 3 allow ip from any to table\(30\)
                  ipfw add 3 allow ip from any to table\(40\)
                  ipfw add 3 allow ip from table\(30\) to any
                  ipfw add 3 allow ip from table\(40\) to any

                  И еще, при всем при этом не заработало, пока не отключил TSO на карте
                    0
                    еще в pf мне кажется стоит упомянуть про rdr
                      0
                      А есть ещё нат который с ppp идёт. Я его везде где pppoe соединения использую, вроде вполне себе нормально работает. Единственный минус, если нужно правило какое-нибудь типа проброса порта добавить, нужно pppoe-сессию перезапускать.
                        +1
                        Касательно первого абзаца раздела «Немного сравнения».
                        Разводить в системе зоопарк из фаерволов очень нежелательно, дабы не ломать лишний раз голову на тему «как пакет пойдёт если огурцы ложка банка майонеза».
                        Для большинства целей подойдёт схема «nat при помощи нетграфа (без заворота трафика через ipfw); фаерволом — pf».
                        Для тех, кому надо нарезать трафик на туеву хучу IP-адресов — организацию ната взять с предыдущей схемы, резалку трафика реализовать на думминете.
                        А два и более фаеров на одной машине — жёппа.
                          0
                          PF не дружит с SMP, соответственно PPS по сравнению с IPFW достаточно низок, сам проверял…
                            +1
                            Ничо, разрабам опенбсд позавчера рассказали про SMP, скоро запилят поддержку :)
                              0
                              Я это скоро уже года 3 как слышу :D
                            0
                            еще я пытался PF атаки отбивать, так вот при использовании динамических таблиц система отказывает во входе. ipfw позволяет зайти, т.к. SMP поддерживается и долгий поиск по таблице не замедляет всю сетевую активность.
                            0
                            В примере для ipfw во втором правиле not table\(10\) лучше заменить на any out или отвлечься и объяснить, зачем нужна эта таблица.
                              0
                              Потому что делать to any дурной тон в общем и целом. Кроме того далеко не все нужно натить — например me и соседние хосты. Давить нат излишними естепблишед сессиями если оные могут нативно раутиться.
                                0
                                Мой парсер сломался на последнем предложении.
                                /* Зачем давить нат излишними естепблишед сессиями если оные могут нативно раутиться по соседям? */
                                  0
                                  Я ж не говорю на боевых серверах так делать. Просто в примере оно смотрится одиноко без описания.
                                    0
                                    Ну в принципе да, можно было для наглядности объявить скажем ipfw table 10 add 200.200.200.0/24 или как-то так.
                              +2
                              Мало именно сравнения и совсем нет холивара — без этого читать неинтересно. :-) Что использует в работе сам автор?

                              natd сейчас практического смысла по сути не имеет — если стоит задача по быстрому дать интернет в офисе, то проще вообще не трогать ipfw, а сделать все сразу на pf — там две строчки написал и уже работает. Ну и в целом — гонять трафик из ядра в user-space — это не дело. Производительность, кстати, измерять в Мегабитах не вполне корректно — лучше, все-таки, в pps.

                              ipfilter — его вообще хоть кто-нибудь использует? Такой же привет из прошлого, как natd…

                              pf — как уже сказано выше — легок и прост в первом приближении. Но т.к. сделан не на libalias — не умеет проксировать активный FTP и еще кое-чего по мелочи — это создает излишний геморрой. Плюс на серьезных нагрузках сильно грузит проц — я его профилировал через hwpmc — там пробег по всем state'ам очень много времени занимает и это не лечится.

                              ng_nat — все-таки вещь не массовая, ИМХО. Хотя я его использовал из любопытства на паре серверов — работал и каши не просил. Но человеку без подготовки netgraph вообще лучше не трогать…

                              ipfw nat — на мой взгляд для серьезных нагрузок оптимальный вариант. Вся мощь libalias'а, никаких заморочек с настройками… Единственная проблема, с которой пришлось в свое время столкнуться — для того, чтобы создать больше сотни (примерно, точно не помню) редиректов пришлось немного патчить ядро — размер буфера там одного увеличить… Но, возможно, в последних версиях Фри это уже поправили — не проверял.

                              Резюмируя, я бы остановился на двух типичных сценариях использования и, соответственно, оптимальных файрволлах/натах:
                              pf — для использования не в телекоммуникациях, а просто с корпоративе, где нет феерических объемов трафика. ipfw не использовать вообще — делать все на pf. Синтаксис очень простой и понятный, мониторинг — удобный, производительность — достаточная для указанных целей
                              ipfw — для серьезного применения. Благо теперь в нем есть все-все-все и это нормально работает. Синтаксис, конечно, сложнее, но это издержки фич. Если pf можно сравнить с языком программирования высокого уровня, то ipfw — ассемблер. :-) Однако, в достаточно большом количестве случаев это все не особенно нужно и не требуется.
                                0
                                Единственное, что в ipfw не хватает, команды для защиты от синфлуда и рейтлимита во временном периоде.
                                  0
                                  А не подскажите как убрать все правила ната?
                                  0
                                  Согласен с Вашей точкой зрения. Сам использую в работе ipfw nat.
                                  А ipfilter все еще встречается мне. Не так часто как остальные, но довольно, чтоб не оставить его без внимания. ng_nat тоже довольно часто встречается, у меня тоже с ним проблем не было никогда — настроил и забыл.
                                    0
                                    > ipfilter — его вообще хоть кто-нибудь использует?

                                    приходится некоторым :) на Solaris другого нет :)
                                    0
                                    Немножко использую pf, но знакомился с ним глубоко, но не пригодилось. Пока он у меня только маршрут следования пакетов меняет в зависимости от источника.
                                      0
                                      А у меня вот так правила написаны:

                                      # Internet settings
                                      oif=«em0»
                                      onet=«84.237.22.0»
                                      mask=«255.255.255.128»
                                      oip=«84.237.22.3»

                                      # Intranet settings
                                      iif=«re0»
                                      inet=«192.168.0.0»
                                      imask=«255.255.255.0»
                                      iip=«192.168.0.1»

                                      # Rules for NAT
                                      ${ipfw} nat 1 config log if ${oif} same_ports
                                      ${ipfw} add 50 nat 1 all from ${inet}:${imask} to any out recv ${iif} xmit ${oif}
                                      ${ipfw} add 50 nat 1 all from any to ${oip} in recv ${oif}

                                      При использовании модификаторов recv и xmit нет надобности использовать: «table\(10\) via em0, где table 10 – не идет через нат», к тому же как мне кажется это намного удобнее нежели использование модификатора via.

                                      Естественно это справедливо только в ряде случаев.
                                        0
                                        Такой вопрос, как увеличить таблицу трансляций для ng_nat?
                                        Я так понимаю надо копаться с libalias, пока только нашел константы в исходниках libalias.

                                        #define LINK_TABLE_OUT_SIZE 4001
                                        #define LINK_TABLE_IN_SIZE 4001

                                        Но неизвестно как отреагирует вся система ну увеличение этих констант.
                                        Может есть какой-то более простой способ?

                                        Второй вопрос, если запускаю 2,3 ноды ng_nat таблица трансляций у них общая, или у каждой ноды своя?
                                          0
                                          + не страдает детскими болезнями типа приколов с одновременными pptp сквозь нат

                                          В PF это решается так
                                          rdr on $ext_if proto {tcp,udp} from any to $exy_if port {1723} -> $vpnserver
                                          rdr on $ext_if proto gre from any to $ext_if -> $vpnserver
                                            0
                                            Классно, теперь бы еще шейпер с классами и список ip из mysql подцепить. :) И как раз то что нужно для нашей сетки

                                            Only users with full accounts can post comments. Log in, please.