Содержание * Введение * Подготовка * Простенький stateful NAT * Перенаправление (redirect) * FTP proxy * Использование отдельного IP-адреса для трансляций на внешнем интерфейсе * Безусловная полная трансляция * Контроль над трансляцией Введение -------- Синдром гамака является одним из ключевых моментов деградации сисадмина. Он начинается с того, что стабильность и неподвижность становятся синонимами. Когда-то, до того, как IPFilter включили в состав FreeBSD, единственным нормальным способом сделать NAT во FreeBSD был natd. Это извращение работало через divert socket и висело демоном. natd до сих пор может быть в некоторых случаях актуален. Мы же рассмотрим использование ipnat из IPFilter в качестве средства для Network Address Translation (NAT). Этот документ не является пошаговым howto for dummies - подразумевается, что не нужно объяснять, что например после изменения /etc/syslog.conf ему нужно послать сигнал HUP, а файлы, куда он будет писать, создавать нужно самостоятельно и как "применять" изменённые правила. Если Вы считаете, что ещё не совсем освоились с *nix и с FreeBSD в частности, то по этой теме можно почитать: ipnat(1), ipnat(5), ipnat(8) ipf(5), ipf(8), ipfstat(8), ipftest(1), ipmon(8) Здесь и далее будет считаться, что IPFilter у нас как минимум версии 3.4.29. Если в Вашем случае это не так - то Вы ещё не совсем вылезли из гамака, хотя уже тот факт, что Вы читаете этот текст, является доказательством Вашего на то желания. Подготовка ---------- Итак, рассмотрим ситуацию: мы имеем 2 интерфейса - fxp0 (200.200.200.1), смотрящий в большой и злой интернет, и dc0 (192.168.0.1), смотрящий во внутреннюю сеть. Задача: сделать возможность пользователям внутренней сети открывать TCP/UDP соединения к внешним хостам без использования socks5/http proxy и т.п. В ядре нам понадобятся всего 2 строчки: options IPFILTER options IPFILTER_LOG После этого IPFilter доступен нам во всей своей красе. Также в /etc/rc.conf нужно добавить строчку gateway_enable="yes" или в /etc/sysctl.conf добавить строчку net.inet.ip.forwarding=1. Теперь всё готово - пакеты перебрасываются между интерфейсами. Осталось контролировать их переброс и заменять в них IP адрес с внутреннего на внешний и наоборот. Простенький stateful NAT ------------------------ Начнём с простого stateful NAT т.е. IP пакеты с внешнего интерфейса для получателя во внутренней сети будут транслироваться только в том случае, если пользователь сам установил это соединение. Все остальные пакеты, пришедшие на внешний интерфейс для получателя во внутренней сети бы будем блокировать (см. redirect далее, если какие-то пакеты извне нужно всегда пробрасывать внутрь). Для соединений, установленных пользователем, мы будем создавать запись в state table с помощью простого правила IPFilter: pass out quick on fxp0 proto tcp from 192.168.1.149 to any flags S/FSRA keep state (для TCP-соединений) и pass out quick on fxp0 proto udp from 192.168.1.149 to any keep state (для UDP-соединений). Можно вместо двух правил сделать одно общее как для TCP, так и для UDP: pass out quick on fxp0 proto tcp/udp from 192.168.1.149 to any keep state однако в таком правиле мы не сможем отслеживать tcp-пакеты с флагом SYN с помощью flags, в результате чего любой пакет из внутренней сети будет создавать запись в state table (если её не было), а не те пакеты, которые являются первыми в установке TCP-соединения (с флагом SYN). Что удобнее/лучше/больше подходит - решайте сами. Следом за этим правилом мы поместим правило, блокирующее все пакеты для внутренней сети: block in quick on fxp0 from any to 192.168.0/16. Под это правило будут попадать пакеты, не являющиеся частью соединений, запрошенных из внутренней сети либо пакеты из соединений, которых нет в state table Теперь сама трансляция. Занесём в файл трансляций (по умолчанию это /etc/ipnat.rules) правило: map fxp0 192.168.1.149/32 -> 200.200.200.1/32 portmap tcp/udp 20000:20099 В результате мы получаем следующую картину: при установке TCP-соединения самый первый пакет (с флагом SYN) из внутренней сети с хоста 192.168.1.149 при уходе в большой и злой интернет будет подвержен простому преобразованию - адрес хоста, запросившего установку соединения будет изменён с 192.168.1.149 на 200.200.200.1. Порт будет также изменён на первый доступный из диапазона от 20000 до 20099. Как можно заметить, в данном случае хост 192.168.1.149 может открыть наружу не более 100 соединений. Всё что осталось - применить правила. ;-) Для удобства отслеживания работы NAT можно добавить строчку в syslog.conf: local0.* /var/log/ipmon.log и запустить утилиту мониторинга работы IPFilter - ipmon с ключами -Dvas (стать демоном, показывать более детальную информацию, отслеживать все утройства IPFilter (NAT, state table и сам IPFilter) и работать через syslog). Если получаемый log-файл кажется сумбурным - не торопитесь включать только NAT опцией -o N. Правила IPFilter попадающие в лог можно туда направлять с другой facility. Для этого достаточно в каждое правило с флагом log добавить facilty: block in log level local2.info quick on fxp0 from any to 192.168.0/16 а в syslog.conf добавить ещё одну строку: local2.* /var/log/ipfilter.block.log. В результате сего деяния в /var/log/ipmon.log будет попадать информация о NAT (созданные трансляции, закрытые трансляции) и state table (создание записи и её удаление), а в файл /var/log/ipfilter.block.log пакеты, которые были блокированы. Если не желаете, чтобы в большом количестве правил была указана facility и правила были короче - можно отвергнуть возможность работы ipmon через syslog и заставить его писать прямо в файл; например так: ipmon -Dv -o NS /var/log/NAT.log (трансляции и state table протоколируем в файл /var/log/NAT.log) и ipmon -Dv -o I /var/log/ipfilter.log (работу самого фильтра протоколируем в файл /var/log/ipfilter.log). Стоит заметить, что одним правилом можно транслировать несколько хостов. Например заменив в правилах ipnat и IPFilter 192.168.1.149/32 на 192.168.128/25 мы будем транслировать пакеты хостов из внутренней сети из диапазона от 192.168.1.128 до 192.168.1.254. Перенаправление (редирект) -------------------------- Если существует необходимость безусловно транслировать какие-то пакеты, пришедшие извне (например чтобы WWW/SMTP сервер из внутренней сети) был доступен снаружи - используется редирект (redirect). Простой вариант: транслировать пакеты от любого хоста. rdr fxp0 200.200.200.1/32 port 8080 -> 192.168.1.17 port 80 tcp В данном случае любой пакет, пришедший на порт 8080 внешнего интерфейса 200.200.200.1 будет "проброшен" на 192.168.1.18 порт 80. Естественно, что хост 192.168.1.17 лучше поместить в таблицу трансляций как было описано в "Простеньком stateful NAT" и с учётом того, что инициироваться соединение будет снаружи - добавить правила IPFilter, которые бы разрешали их. В случае, если ipmon протоколирует работу IPFilter, допущенную ошибку можно будет легко увидеть. Редирект можно делать не всех пакетов, а выборочно на основании их отправителя: rdr fxp0 from 212.118.165.100/32 to 200.200.200.1/32 port = 6000 -> 192.168.1.89 port 6000 Этим правилом будут транслироваться пакеты, пришедшие на 200.200.200.1 порт 6000 только с хоста 212.118.165.100 Не стоит забывать создавать правила IPFilter, разрешающие прохождение таких пакетов. Хотя, если ipmon настроен и запущен, то он быстро об этом напомнит. ;-) FTP proxy --------- Итак, всё работает замечательно, за исключением FTP. Это обусловлено тем, что в ходе установки соединения, по которому будут передаваться данные, указывается IP-адрес клиента, который в нашем случае принадлежит частной сети. ipnat способен в таких случаях быть "прокси-сервером" - то есть "ковыряться" в данных, передаваемых FTP-серверу и от него, и транслировать адреса из внутренних во внешние и наоборот. Для этого используется такое правило: map fxp0 192.168.1.149/32 -> 200.200.200.1/32 proxy port ftp ftp/tcp proxy-правило должно обязательно стоять перед другими правилами (за исключением redirect). Использование отдельного IP-адреса для трансляций на внешнем интерфейсе ----------------------------------------------------------------------- Если у Вас имеется в наличии не 1 IP-адрес, а сегмент сети, может быть удобным транслировать не с тех адресов, которые установлены на внешнем интерфейсе (fxp0), а с других. При этом важным является то, что на самом внешнем интерфейсе (fxp0) этот IP-адрес устанавливать нет никакой необходимости. ipnat делая трансляцию не открывает сокетов - об этом нужно помнить. Допустим, что сеть 200.200.200.0/24 полностью принадлежит нам. В таком случае, во всех правилах трансляции мы можем ставить не реальный IP-адрес, установленный на внешнем интерфейсе (fxp0), а другой, например 200.200.200.200 (также можно по желанию сделать PTR запись для этого хоста в зоне 200.200.200.in-addr.arpa). Безусловная полная трансляция ----------------------------- Если существует необходимость транслировать абсолютно все пакеты, пришедшие на какой-либо адрес (не забывайте, что этот IP-адрес необязательно должен быть установлен на внешнем интерфейсе fxp0) - используется правило bimap. bimap fxp0 192.168.1.66/32 -> 200.200.200.100/32 и/или bimap fxp0 192.168.1.66/32 -> 200.200.200.100/32 portmap tcp/udp Контроль над трансляцией ------------------------ Безусловно глупо настраивать NAT не глядя в протоколы, генерируемые ipmon`ом. Также возможно будет полезным ограничивать способность устанавливать соединения изнутри к привилегированным портам внешних хостов. Всё это можно и нужно настроить по желанию.