[Информационная безопасность, Системное администрирование, IT-инфраструктура, Софт] FreeBSD. Трансляции, тэги и якоря в PF
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
- Файрвол PF в ОС FreeBSD
- FreeBSD. Фильтрация трафика PF
- FreeBSD. Трансляции, тэги и якоря в PF <- Вы здесь
Введение
В прошлых статьях мы разобрали, что такое PF вообще, общие принципы построения правил. Узнали о таблицах и способах фильтрации трафика PF. И создали конфигурационные файлы, которые способны защитить сервер в Интернет. В этой статье попробуем разобраться с NAT трансляциями и тэгами (tags). Еще пройдемся по якорям (anchors), их иногда называют еще закладками.
Думаю, объяснять, что такое NAT трансляции в общем случае не стоит. PF поддерживает три вида трансляций.
Anchors — это отдельные наборы правил PF, которыми, подобно таблицам, можно управлять динамически.
Tag — это способ пометить пакет, чтобы потом обработать в другом правиле. Удобно, например, метить пакеты, проходящие через проброс, чтобы потом их разрешить скопом в одном правиле.
Задача
Сразу оговоримся, что конфигурация вполне рабочая, но, для упрощения, везде будут использоваться "серые" сети.
У нас есть офис. Обычный офис, 2 локальные сети.
В сети 172.16.2.0/24 находится бухгалтерия. Ну и главный бухгалтер, особое отношение 172.16.2.2.
Во второй сети — 172.16.3.0/24 находится сервер (172.16.3.1), который надо странслировать в интернет 1 в 1. Компьютер системного администратора, особое отношение плюс надо сделать проброс порта для торрентов (59715 TCP и UDP). Компьютер директора, особое отношение.
Кроме того, нужно запретить ходить на сайты социалочек, для примера возьмем несколько доменов вроде vk.com и facebook.com, для всех, кроме избранных. И сделать для штрафников запрет входа в интернет, кроме нескольких сайтов, пусть будут google.com и yandex.ru, необходимых для работы.
Всем нужно ходить только до сервера в Интернет, 172.16.1.2. Провайдер нам даёт сеть 172.16.1.1/24 со шлюзом 172.16.1.254 и дополнительный IP для внутреннего сервера 172.16.1.5.
Подготовка
Для начала подготовим наш роутер. Пусть сетевые интерфейсы и маршрут по умолчанию уже настроен.
Во-первых нужно добавить возможность маршрутизации. Для этого в /etc/rc.conf добавляем строку:
gateway_enable="yes"
И перезагружаем машину.
Всё, маршрутизация уже работает.
Добавляем макросов, таблиц, скраб, опции, очереди (которых нет)
SPL
#macros section
ExtIf="re0" # внешний интерфейс
IntIf1="em0" # локальный 0, бухгалтерия
IntIf2="em1" # локальный 1, всё остальное.
ExtIfIp1="172.16.1.1" # Внешний IP адрес
ExtIfIp2="172.16.1.5" # Дополнительный адрес от провайдера
IntIf1Ip="172.16.2.254" # IP локального 0
IntIf1Net="172.16.2.0/24"
IntIf2Ip="172.16.3.254" # IP локального 1
IntIf2Net="172.16.3.0/24"
IntSrv="172.16.3.1"
ExtSrv="172.16.1.2"
torrent_port="59715"
permit_tcp_ports="22,53"
permit_udp_ports="53,123"
web_ports = "http,https"
permit_corp_ports ="http,https"
permit_add_tcp_ports = "8080,8443"
#table section
table <privileged_If1> { 172.16.2.2 } # главбух и избранные из бухгалтерии
table <privileged_If2> { 172.16.3.15, 172.16.3.125 } # избранные из общей сети
table <bad_users> persist # табличка для тех, кто нам не нравится
table <block_list> file "/etc/pf.blocklist.conf" # хосты, которые нам просто не нравятся, находятся тут
table <corp_res> file "/etc/pf.corpres.conf"# корпоративные ресурсы, доступ по hppt(s)
table <sites_for_all> file "/etc/pf.sitesforall.conf" # сайты, доступные всем
table <bad_sites> file "/etc/pf.badsites.conf"
table <block_ssh> persist # Брутфорсеры ssh. если таблица пустая, PF её удалит. Для отмены такого поведения используется ключевое слово persist
table <block_web> persist # заблокированный доступ до веб до сервера
#options section
set block-policy return # разрываем соединения с ответом, а не просто дропаем пакеты
set skip on lo0 # пропускаем проверку на локальной петле, там фильтрация не нужна
#scrub section
scrub in all # нормализация всего входящего трафика
#Queueing section
# в данный момент пустая
Трансляции
Время добавить немного трансляций. Правила строятся по общему синтаксису (описан во вводной статье). Однако добавилось исключение действия.
PF поддерживает 3 типа.
- binat — двунаправленная трансляция, статическая трансляция, или трансляция один в один в оба направления.
- nat — source nat, подмена источника. То, что называют NAT почти везде.
- rdr — проброс портов, трансляция адреса назначения, destination nat, dnat.
BINAT
Начнем со статической трансляции. Синтаксис команды (из официальной документации):
[ "no" ] "binat" [ "pass" [ "log" [ "(" logopts ")" ] ] ]
[ "on" interface-name ] [ af ]
[ "proto" ( proto-name | proto-number ) ]
"from" address [ "/" mask-bits ] "to" ipspec
[ "tag" string ] [ "tagged" string ]
[ "->" address [ "/" mask-bits ] ]
Все параметры примерно те же, что и с правилами фильтрации, кроме no в начале. Это как раз то самое исключение. Если поставить его над правилом трансляции, попадающий под него трафик странслирован не будет. Выглядит это так:
no binat on $ExtIf from $IntSrv to 172.16.34.0/24
binat on $ExtIf from $IntSrv to any -> $ExtIfIp2
Это означает, что весь трафик, кроме исключения, от хоста IntSrv (172.16.3.1) будет при выходе в интернет странслирован в адрес ExtIfIp2(172.16.1.5), и наоборот, всё, что пришло из интернета на этот внешний адрес, улетит на наш сервер. Удобно, когда надо пробросить кучу портов, и в некоторых других случаях. Например для выделенной АТС. В конфигурацию пойдет вот такое правило:
binat on $ExtIf from $IntSrv to any -> $ExtIfIp2
NAT
Теперь — NAT из локальной сети в Интернет. Синтаксис правила:
[ "no" ] "nat" [ "pass" [ "log" [ "(" logopts ")" ] ] ]
[ "on" ifspec ] [ af ]
[ protospec ] hosts [ "tag" string ] [ "tagged" string ]
[ "->" ( redirhost | "{" redirhost-list "}" )
[ portspec ] [ pooltype ] [ "static-port" ] ]
И строка в конфиге:
nat on $ExtIf from { $IntIf1Net, $IntIf2Net } to any -> $ExtIfIp1
Это правило говорит о том, что всё, идущее в интернет нужно закрыть первым IP внешнего интерфейса. Можно поставить исключения, подобно binat. Кроме обычной трансляции в один статический IP, можно, например, чтобы PF сам вычислял этот IP с интерфейса. Полезно, если провайдер даёт динамический IP по PPPoE или DHCP:
nat on $ExtIf from { $IntIf1Net, $IntIf2Net } to any -> ($ExtIf)
Если на интерфейсе несколько IP, или сеть то её можно указать как напрямую, так и используя такой синтаксис, будет указана вся сеть внешнего интерфейса (поддерживается только round-robin):
nat on $ExtIf from { $IntIf1Net, $IntIf2Net } to any -> ($ExtIf:network)
По умолчанию PF будет распределять соответствие соединений и внешний IP по стратегии round-robin. Это поведение можно поменять, используя явное указание сети. Доступны ещё стратегии source-hash, когда он выбирает для каждого адреса IP из получившегося пула, основываясь на внутреннем, либо случайный выбор random. Можно включить прилипание, sticky-address, гарантирующее, что один внутренний IP всегда будет закрываться одним и тем же внешним, пока есть живые соединения. Если живых соединений нет, то адрес отлипает:
nat on $ExtIf from { $IntIf1Net, $IntIf2Net } to any -> 172.16.1.0/27 \
source-hash sticky-address
RDR
Ну и последнее, проброс портов. Отличий мало.
[ "no" ] "nat" [ "pass" [ "log" [ "(" logopts ")" ] ] ]
[ "on" ifspec ] [ af ]
[ protospec ] hosts [ "tag" string ] [ "tagged" string ]
[ "->" ( redirhost | "{" redirhost-list "}" )
[ portspec ] [ pooltype ] [ "static-port" ] ]
Правило в конфиг:
rdr on $ExtIf inet proto {tcp, udp} from any to $ExtIfIp1 \
port { $torrent_port } -> 172.16.3.15 port $torrent_port
Правило завернет входящие пакеты на IP администратора. Из дополнительных возможностей — можно организовать простенький балансировщик:
rdr on $ExtIf inet proto {tcp, udp} from any to $ExtIfIp1 \
port { $torrent_port } -> { 172.16.3.15, 172.16.3.15 } \
port $torrent_port round-robin
Ну и, как и везде, выше можно поставить исключение.
Тэги
- В одно время у пакета может быть только один тэг
- Правило может переопределить тэг пакета, но не удалить его
- Правила отбора можно инвертировать знаком отрицания перед ключевым словом:! tagged PASS
Тэг (tag) — это способ пометить пакет, прошедший по правилу, для дальнейшей обработки. Для понимания, в чем волшебство момента, нужно немного разобраться с тем, как пакет проходит по PF.
В случае обычного хоста всё просто. Есть интерфейсы, есть входящий на них трафик, есть исходящий, который производит сам хост. Однако в случае маршрутизатора пакет сперва входит на интерфейс, проходит по соответствующим правилам in, вроде:
pass in quick on $IntIf1 from $IntIf1Net to $IntIf2Net
затем, перед выходом с другого интерфейса, проходит по правилам out:
pass out quick on $IntIf2 from $IntIf1Net to $IntIf2Net
и, если нам нужно просто разрешить ходить между двумя своими локальными сетями, приходится делать четыре правила:
pass in quick on $IntIf1 from $IntIf1Net to $IntIf2Net
pass out quick on $IntIf2 from $IntIf1Net to $IntIf2Net
pass in quick on $IntIf2 from $IntIf2Net to $IntIf1Net
pass out quick on $IntIf1 from $IntIf2Net to $IntIf1Net
Есть два варианта избежать этого. Первый — не указывать интерфейсы и направления. Соорудить что-то вроде:
pass quick from $IntIf1Net to $IntIf2Net
Но, это не наши методы, потому что снижает "строгость" файрвола.
Решение подобной проблемы очень простое:
pass in quick on $IntIf1 from $IntIf1Net to $IntIf2Net tag PASS
pass in quick on $IntIf2 from $IntIf2Net to $IntIf1Net tag PASS
pass out tagged PASS
Тэг, сохраняясь на всём пути прохождения пакета, в конце концов попадёт на правило pass out, и трафик пройдёт.
Такой приём позволяет сократить количество правил и выстроить более логичную и простую их структуру. Точно так же можно, к примеру, блокировать трафик на части интерфейсов.
А еще правила фильтрации PF, в случае, если на интерфейсе есть трансляция, увидят уже странслированные пакеты.
В результате на исходящем интерфейсе не всегда можно однозначно понять, откуда пришел пакет. К примеру правило, разрешающее торрент администратора, на внешнем интерфейсе, будет использовать локальный IP:
pass in on $ExtIf proto { tcp, udp } from any to 172.16.3.15 \
port { $torrent_port } tag PASS
Если собрать всё в кучу, то, на данный момент, получится следующее
SPL
######## macros section ########
ExtIf="re0" # внешний интерфейс
IntIf1="em0" # локальный 0, бухгалтерия
IntIf2="em1" # локальный 1, всё остальное.
ExtIfIp1="172.16.1.1" # Внешний IP адрес
ExtIfIp2="172.16.1.5" # Дополнительный адрес от провайдера
IntIf1Ip="172.16.2.254" # IP локального 0
IntIf1Net="172.16.2.0/24"
IntIf2Ip="172.16.3.254" # IP локального 1
IntIf2Net="172.16.3.0/24"
IntSrv="172.16.3.1"
ExtSrv="172.16.1.2"
torrent_port="59715"
permit_tcp_ports="22,53"
permit_udp_ports="53,123"
web_ports = "http,https"
permit_corp_ports ="http,https"
permit_add_tcp_ports = "8080,8443"
######## table section ########
table <privileged_If1> { 172.16.2.2 } # главбух и избранные из бухгалтерии
table <privileged_If2> { 172.16.3.15, 172.16.3.125 } # избранные из общей сети
table <bad_users> persist # табличка для тех, кто нам не нравится
# хосты, которые нам просто не нравятся, находятся тут
table <block_list> file "/etc/pf.blocklist.conf"
# корпоративные ресурсы, доступ по hppt(s)
table <corp_res> file "/etc/pf.corpres.conf"
table <sites_for_all> file "/etc/pf.sitesforall.conf" # сайты, доступные всем
table <bad_sites> file "/etc/pf.badsites.conf"
# Брутфорсеры ssh. если таблица пустая, PF её удалит. Для отмены такого поведения используется ключевое слово persist
table <block_ssh> persist
# заблокированный доступ до веб до сервера
table <block_web> persist
######## options section ########
# разрываем соединения с ответом, а не просто дропаем пакеты
set block-policy return
# пропускаем проверку на локальной петле, там фильтрация не нужна
set skip on lo0
#scrub section
# нормализация всего входящего трафика
scrub in all
#Queueing section
# в данный момент пустая
######## nat section ########
#статическая трансляция для сервера
binat on $ExtIf from $IntSrv to any -> $ExtIfIp2
#NAT для клиентов
nat pass on $ExtIf from { $IntIf1Net, $IntIf2Net } to any -> $ExtIfIp1
# прооброс портов на машину администратора
rdr on $ExtIf inet proto {tcp, udp} from any to $ExtIfIp1 port { $torrent_port } -> 172.16.3.15 port $torrent_port
rdr on $ExtIf inet proto {tcp, udp} from any to $ExtIfIp1 \
port { $torrent_port } -> { 172.16.3.15, 172.16.3.15 } port $torrent_port round-robin
######## filtering section ########
# запрет всего по умолчанию, помним, что это не означает окончание обработки пакета.
block log all
## Разрешения для входящих пакетов из Интернет. ##
# разрешаем ssh с защитой от брутфорса
block in quick proto tcp from <block_ssh> port 22
pass in quick on $ExtIf proto tcp to { $ExtIfIp1 $IntSrv } port { 22 } \
keep state (max-src-conn 10, max-src-conn-rate 3/10, \
overload <block_ssh> flush) tag PASS
# разрешаем Web с защитой от ботов и прочего
block in quick on $ExtIf from <block_web>
pass in on $ExtIf proto tcp to $IntSrv port { $web_ports } \
synproxy state (max-src-conn 100, max-src-conn-rate 20/1, \
overload <block_web> flush global) tag PASS
# разрешаем ходить торрентам
pass in on $ExtIf proto { tcp, udp } from any to 172.16.3.15 port { $torrent_port } tag PASS
## Разрешения для внутренних сетей ##
# разрешаем серверу ходить до корпоративных ресурсов
pass in quick on $IntIf2 proto tcp from $ExtIfIp2 to $ExtSrv port { $web_ports, $permit_corp_ports, $permit_add_tcp_ports } tag PASS
# Если надо разрешить ему ходить в интернет, то раскомментируем
# pass in quick on $IntIf2 from $IntSrv to any tag PASS
# разрешаем ходить между локалками всем
pass in quick on $IntIf1 from $IntIf1Net to $IntIf2Net tag PASS
pass in quick on $IntIf2 from $IntIf2Net to $IntIf1Net tag PASS
# разрешаем всё привилегированным пользователям
pass in on $IntIf1 from <privileged_If1> to any tag PASS
pass in on $IntIf2 from <privileged_If2> to any tag PASS
# разрешаем ДНС, icmp всем
pass in quick on $IntIf1 proto tcp from ($IntIf1:network) to any port { $permit_tcp_ports } tag PASS
pass in quick on $IntIf2 proto tcp from ($IntIf2:network) to any port { $permit_tcp_ports } tag PASS
# разрешаем всем корпоративные ресурсы
pass in quick on $IntIf1 proto tcp from ($IntIf1:network) to $ExtSrv port { $web_ports } tag PASS
pass in quick on $IntIf2 proto tcp from ($IntIf2:network) to $ExtSrv port { $web_ports } tag PASS
pass in quick on $IntIf1 from ($IntIf1:network) to <sites_for_all> tag PASS
pass in quick on $IntIf2 from { $IntIf2Net } to <sites_for_all> tag PASS
block in quick from <bad_users> to any
block in quick from { $IntIf1Net, $IntIf2Net } to <bad_sites>
pass in quick from { $IntIf1Net,$IntIf2Net } to any tag PASS
## разрешаем исходящий трафик ##
pass out log tagged PASS
pass out on { $IntIf1,$IntIf2 }
# разрешаем самому хосту ходить на некоторые порты
pass out quick on $ExtIf proto tcp from ($ExtIf) to any port { $permit_tcp_ports }
pass out quick on $ExtIf proto udp from ($ExtIf) to any port { $permit_udp_ports }
Вполне рабочий конфигурационный файл PF, который сделает всё, что нужно. Однако можно сделать еще лучше.
Якоря
Так же известные как anchors. Это отдельные наборы правил PF. Основные свойства:
- Якоря могут содержать другие якоря, выстраиваясь в древовидную структуру
- Якорь можно загружать из файла
- Якорями можно управлять динамически. Удалять, добавлять правила, etc
- Макросы необходимо определить в том же файле, что и якорь
Есть несколько способов определения якорей:
- nat-anchor исполнит правила nat
rdr-anchor исполнит правила rdr
binat-anchor исполнит правила binat
anchor исполнит правила фильтрации
load anchor from команда загрузки из файла
Во время определения anchor так же можно указать, какой трафик будет отправлен в него.
Простое определение anchor с загрузкой из файла:
anchor localnet1
load anchor localnet1 from "/etc/pf-anchor.localnet1.conf"
Можно обойтись и без загрузки из файла, просто определить anchor первой строкой, затем подгружать в него правила из командной строки.
# echo "pass in quick on $IntIf1 from $IntIf1Net to $IntIf2Net tag PASS" | \
pfctl -a localnet1 -f -
Просмотреть правила, добавленные в якорь:
# pfctl -a "localnet1" -sr
Вывод будет похож на pfctl -sr, потому что корневой конфигурационный файл — это просто корневой якорь.
Перезагрузить якорь из файла:
# pfctl -a "localnet1" -f /etc/pf-anchor.localnet1.conf
Удалить все правила из якоря:
# pfctl -a "localnet1" -F rules
Anchor в конфигурационном файле вызывается по месту определения. Как и обычное правило, можно сделать anchor с условиями:
anchor localnet1 in on $IntIf1 from any to any
Можно определить якорь фильтрации вместе с условиями прямо по месту, используя фигурные скобки:
anchor "localnet1" in on $IntIf1 {
pass in quick on $IntIf1 from $IntIf1Net to $IntIf2Net tag PASS
pass in quick on $IntIf1 proto tcp from ($IntIf1:network) to any \
port { $permit_tcp_ports } tag PASS
}
Если внутри якоря в правиле указана опция quick, то обработка прекращается для всех правил файрволла, в том числе и после него. Можно так же указать опцию quick для определения anchor, тогда обработка остановится на последнем правиле этого набора. Метки так же сохранятся.
Внутри якоря можно так же определять таблицы. Они будут видны в этом и всех вложенных якорях.
Теперь можно перенести все правила, относящиеся к входящему трафику на интерфейсе $IntIf1 в anchor, загружаемый из файла. Не забываем макросы.
###### macros section ######
IntIf1="em0" # локальный 0, бухгалтерия
IntIf1Ip="172.16.2.254" # IP локального
IntIf1Net="172.16.2.0/24"
IntIf2Net="172.16.3.0/24"
ExtSrv="172.16.1.2"
permit_tcp_ports="22,53"
permit_udp_ports="53,123"
web_ports = "http,https"
###### filter section ######
# разрешаем ходить между локалками всем
pass in quick on $IntIf1 from $IntIf1Net to $IntIf2Net tag PASS
# разрешаем всё привелигированным пользователям
pass in on $IntIf1 from <privileged_If1> to any tag PASS
# разрешаем ДНС, icmp всем
pass in quick on $IntIf1 proto tcp from ($IntIf1:network) to any port { $permit_tcp_ports } tag PASS
# разрешаем всем корпоративные ресурсы
pass in quick on $IntIf1 proto tcp from ($IntIf1:network) to $ExtSrv port { $web_ports } tag PASS
# правила для сайтов
pass in quick on $IntIf1 from ($IntIf1:network) to <sites_for_all> tag PASS
block in quick from <bad_users> to any
block in quick from { $IntIf1Net } to <bad_sites>
pass in quick from { $IntIf1Net } to any tag PASS
[spoiler=""]SPL
######## macros section ########
ExtIf="re0" # внешний интерфейс
IntIf1="em0" # локальный 0, бухгалтерия
IntIf2="em1" # локальный 1, всё остальное.
ExtIfIp1="172.16.1.1" # Внешний IP адрес
ExtIfIp2="172.16.1.5" # Дополнительный адрес от провайдера
IntIf1Ip="172.16.2.254" # IP локального 0
IntIf1Net="172.16.2.0/24"
IntIf2Ip="172.16.3.254" # IP локального 1
IntIf2Net="172.16.3.0/24"
IntSrv="172.16.3.1"
ExtSrv="172.16.1.2"
torrent_port="59715"
permit_tcp_ports="22,53"
permit_udp_ports="53,123"
web_ports = "http,https"
permit_corp_ports ="http,https"
permit_add_tcp_ports = "8080,8443"
######## table section ########
table <privileged_If1> { 172.16.2.2 } # главбух и избранные из бухгалтерии
table <privileged_If2> { 172.16.3.15, 172.16.3.125 } # избранные из общей сети
table <bad_users> persist # табличка для тех, кто нам не нравится
# хосты, которые нам просто не нравятся, находятся тут
table <block_list> file "/etc/pf.blocklist.conf"
# корпоративные ресурсы, доступ по hppt(s)
table <corp_res> file "/etc/pf.corpres.conf"
table <sites_for_all> file "/etc/pf.sitesforall.conf" # сайты, доступные всем
table <bad_sites> file "/etc/pf.badsites.conf"
# Брутфорсеры ssh. если таблица пустая, PF её удалит. Для отмены такого поведения используется ключевое слово persist
table <block_ssh> persist
# заблокированный доступ до веб до сервера
table <block_web> persist
######## options section ########
# разрываем соединения с ответом, а не просто дропаем пакеты
set block-policy return
# пропускаем проверку на локальной петле, там фильтрация не нужна
set skip on lo0
#scrub section
# нормализация всего входящего трафика
scrub in all
#Queueing section
# в данный момент пустая
######## nat section ########
#статическая трансляция для сервера
binat on $ExtIf from $IntSrv to any -> $ExtIfIp2
#NAT для клиентов
nat pass on $ExtIf from { $IntIf1Net, $IntIf2Net } to any -> $ExtIfIp1
# проброс портов на машину администратора
rdr on $ExtIf inet proto {tcp, udp} from any to $ExtIfIp1 port { $torrent_port } -> 172.16.3.15 port $torrent_port
rdr on $ExtIf inet proto {tcp, udp} from any to $ExtIfIp1 \
port { $torrent_port } -> { 172.16.3.15, 172.16.3.15 } port $torrent_port round-robin
######## filtering section ########
# запрет всего по умолчанию, помним, что это не означает окончание обработки пакета.
block log all
## Разрешения для входящих пакетов из Интернет. ##
# разрешаем ssh с защитой от брутфорса
block in quick proto tcp from <block_ssh> port 22
pass in quick on $ExtIf proto tcp to { $ExtIfIp1 $IntSrv } port { 22 } \
keep state (max-src-conn 10, max-src-conn-rate 3/10, \
overload <block_ssh> flush) tag PASS
# разрешаем Web с защитой от ботов и прочего
block in quick on $ExtIf from <block_web>
pass in on $ExtIf proto tcp to $IntSrv port { $web_ports } \
synproxy state (max-src-conn 100, max-src-conn-rate 20/1, \
overload <block_web> flush global) tag PASS
# разрешаем ходить торрентам
pass in on $ExtIf proto { tcp, udp } from any to 172.16.3.15 port { $torrent_port } tag PASS
## Разрешения для внутренних сетей ##
# разрешаем серверу ходить до корпоративных ресурсов
pass in quick on $IntIf2 proto tcp from $ExtIfIp2 to $ExtSrv port { $web_ports, $permit_corp_ports, $permit_add_tcp_ports } tag PASS
# Если надо разрешить ему ходить в интернет, то раскомментируем
# pass in quick on $IntIf2 from $IntSrv to any tag PASS
anchor localnet1 in on $IntIf1 from any to any
load anchor localnet1 from "/etc/pf-anchor.localnet1.conf"
anchor localnet2 in on $IntIf2 {
# разрешаем ходить между локалками всем
pass in quick on $IntIf2 from $IntIf2Net to $IntIf1Net tag PASS
# разрешаем всё привилегированным пользователям
pass in on $IntIf2 from <privileged_If2> to any tag PASS
# разрешаем ДНС, icmp всем
pass in quick on $IntIf2 proto tcp from ($IntIf2:network) to any port { $permit_tcp_ports } tag PASS
# разрешаем всем корпоративные ресурсы
pass in quick on $IntIf2 proto tcp from ($IntIf2:network) to $ExtSrv port { $web_ports } tag PASS
# правила для сайтов
pass in quick on $IntIf2 from { $IntIf2Net } to <sites_for_all> tag PASS
block in quick from <bad_users> to any
block in quick from { $IntIf2Net } to <bad_sites>
pass in quick from { $IntIf2Net } to any tag PASS
}
## разрешаем исходящий трафик ##
pass out log tagged PASS
pass out on { $IntIf1,$IntIf2 }
# разрешаем самому хосту ходить на некоторые порты
pass out quick on $ExtIf proto tcp from ($ExtIf) to any port { $permit_tcp_ports }
pass out quick on $ExtIf proto udp from ($ExtIf) to any port { $permit_udp_ports }
Таким образом можно оптимизировать по скорости, упорядочить, или просто сделать конфигурацию PF короче и более читаемой. Кроме того, правильно созданной конфигурацией довольно легко управлять динамически, не перезагружая PF.
Заключение
В этот раз мы разобрались с трансляциями, тэгами и якорями. Это последние из базовых возможностей PF, о которых я хотел рассказать в этом цикле. Создали конфигурацию, способную защитить небольшой офис. Для более углубленного изучения стоит обратиться к man pf.conf, а так же официальной документации OpenBSD. Однако того, что рассказано в этих статьях должно хватить для решения большинства задач. Если какая-то тема не раскрыта, или раскрыта не полностью, пишите комментарии, обсудим. Возможно, в следующей статье будет разбор policy-based routing, условной маршрутизации.
Традиционно, приглашаю всех протестировать наше решение — шлюз безопасности Интернет Контроль Сервер, в основе которого лежит обожаемая нами система FreeBSD, а еще есть куча полезных функций для защиты сети, управления юзерами и фильтрации контента. Скачать можно тут. Триал 35 дней, есть бесплатная версия на 9 пользователей.
===========
Источник:
habr.com
===========
Похожие новости:
- [Информационная безопасность, Конференции] Мы с серьезным приглашением
- [Браузеры, Разработка под Windows, Софт] Windows 10 при установке с диска иногда не устанавливает Edge
- [Python, Машинное обучение, Искусственный интеллект, Natural Language Processing] LIT – Инспектор для вашего NLP. Обзор, установка, тест
- [Разработка мобильных приложений, Машинное обучение, Искусственный интеллект, Natural Language Processing] OpenAI: более 300 сторонних приложений работают на GPT-3
- [Децентрализованные сети, Информационная безопасность, Машинное обучение, Искусственный интеллект] Роевое обучение: превратите распределенные данные в фактор успеха
- [Информационная безопасность, Браузеры, IT-компании] Я тебя найду по JS, или какие возможности для фингепринтинга дают современные web-технологии
- [Информационная безопасность, Производство и разработка электроники, Процессоры, IT-компании] Positive Technologies нашла в процессорах Intel Atom две критических уязвимости, производитель проверяет эту информацию
- [Микросервисы] Бессерверные функции для микросервисов — хорошее решение, но не забывайте про гибкость (перевод)
- [Информационная безопасность, Читальный зал] Юристы использовали овчину в качестве средства борьбы с мошенничеством в течение сотен лет (перевод)
- [Информационная безопасность, Ненормальное программирование, Исследования и прогнозы в IT] Как я нашел в публичном доступе исходники нескольких сервисов ФНС
Теги для поиска: #_informatsionnaja_bezopasnost (Информационная безопасность), #_sistemnoe_administrirovanie (Системное администрирование), #_itinfrastruktura (IT-инфраструктура), #_soft (Софт), #_internet_kontrol_server (интернет контроль сервер), #_iks (икс), #_freebsd, #_pf_firewall, #_nat, #_anchor, #_blog_kompanii_internet_kontrol_server (
Блог компании Интернет Контроль Сервер
), #_informatsionnaja_bezopasnost (
Информационная безопасность
), #_sistemnoe_administrirovanie (
Системное администрирование
), #_itinfrastruktura (
IT-инфраструктура
), #_soft (
Софт
)
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 12:37
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
Введение В прошлых статьях мы разобрали, что такое PF вообще, общие принципы построения правил. Узнали о таблицах и способах фильтрации трафика PF. И создали конфигурационные файлы, которые способны защитить сервер в Интернет. В этой статье попробуем разобраться с NAT трансляциями и тэгами (tags). Еще пройдемся по якорям (anchors), их иногда называют еще закладками. Думаю, объяснять, что такое NAT трансляции в общем случае не стоит. PF поддерживает три вида трансляций. Anchors — это отдельные наборы правил PF, которыми, подобно таблицам, можно управлять динамически. Tag — это способ пометить пакет, чтобы потом обработать в другом правиле. Удобно, например, метить пакеты, проходящие через проброс, чтобы потом их разрешить скопом в одном правиле. Задача Сразу оговоримся, что конфигурация вполне рабочая, но, для упрощения, везде будут использоваться "серые" сети. У нас есть офис. Обычный офис, 2 локальные сети. В сети 172.16.2.0/24 находится бухгалтерия. Ну и главный бухгалтер, особое отношение 172.16.2.2. Во второй сети — 172.16.3.0/24 находится сервер (172.16.3.1), который надо странслировать в интернет 1 в 1. Компьютер системного администратора, особое отношение плюс надо сделать проброс порта для торрентов (59715 TCP и UDP). Компьютер директора, особое отношение. Кроме того, нужно запретить ходить на сайты социалочек, для примера возьмем несколько доменов вроде vk.com и facebook.com, для всех, кроме избранных. И сделать для штрафников запрет входа в интернет, кроме нескольких сайтов, пусть будут google.com и yandex.ru, необходимых для работы. Всем нужно ходить только до сервера в Интернет, 172.16.1.2. Провайдер нам даёт сеть 172.16.1.1/24 со шлюзом 172.16.1.254 и дополнительный IP для внутреннего сервера 172.16.1.5. Подготовка Для начала подготовим наш роутер. Пусть сетевые интерфейсы и маршрут по умолчанию уже настроен. Во-первых нужно добавить возможность маршрутизации. Для этого в /etc/rc.conf добавляем строку: gateway_enable="yes"
И перезагружаем машину. Всё, маршрутизация уже работает. Добавляем макросов, таблиц, скраб, опции, очереди (которых нет)SPL#macros section
ExtIf="re0" # внешний интерфейс IntIf1="em0" # локальный 0, бухгалтерия IntIf2="em1" # локальный 1, всё остальное. ExtIfIp1="172.16.1.1" # Внешний IP адрес ExtIfIp2="172.16.1.5" # Дополнительный адрес от провайдера IntIf1Ip="172.16.2.254" # IP локального 0 IntIf1Net="172.16.2.0/24" IntIf2Ip="172.16.3.254" # IP локального 1 IntIf2Net="172.16.3.0/24" IntSrv="172.16.3.1" ExtSrv="172.16.1.2" torrent_port="59715" permit_tcp_ports="22,53" permit_udp_ports="53,123" web_ports = "http,https" permit_corp_ports ="http,https" permit_add_tcp_ports = "8080,8443" #table section table <privileged_If1> { 172.16.2.2 } # главбух и избранные из бухгалтерии table <privileged_If2> { 172.16.3.15, 172.16.3.125 } # избранные из общей сети table <bad_users> persist # табличка для тех, кто нам не нравится table <block_list> file "/etc/pf.blocklist.conf" # хосты, которые нам просто не нравятся, находятся тут table <corp_res> file "/etc/pf.corpres.conf"# корпоративные ресурсы, доступ по hppt(s) table <sites_for_all> file "/etc/pf.sitesforall.conf" # сайты, доступные всем table <bad_sites> file "/etc/pf.badsites.conf" table <block_ssh> persist # Брутфорсеры ssh. если таблица пустая, PF её удалит. Для отмены такого поведения используется ключевое слово persist table <block_web> persist # заблокированный доступ до веб до сервера #options section set block-policy return # разрываем соединения с ответом, а не просто дропаем пакеты set skip on lo0 # пропускаем проверку на локальной петле, там фильтрация не нужна #scrub section scrub in all # нормализация всего входящего трафика #Queueing section # в данный момент пустая Трансляции Время добавить немного трансляций. Правила строятся по общему синтаксису (описан во вводной статье). Однако добавилось исключение действия. PF поддерживает 3 типа.
BINAT Начнем со статической трансляции. Синтаксис команды (из официальной документации): [ "no" ] "binat" [ "pass" [ "log" [ "(" logopts ")" ] ] ]
[ "on" interface-name ] [ af ] [ "proto" ( proto-name | proto-number ) ] "from" address [ "/" mask-bits ] "to" ipspec [ "tag" string ] [ "tagged" string ] [ "->" address [ "/" mask-bits ] ] Все параметры примерно те же, что и с правилами фильтрации, кроме no в начале. Это как раз то самое исключение. Если поставить его над правилом трансляции, попадающий под него трафик странслирован не будет. Выглядит это так: no binat on $ExtIf from $IntSrv to 172.16.34.0/24
binat on $ExtIf from $IntSrv to any -> $ExtIfIp2 Это означает, что весь трафик, кроме исключения, от хоста IntSrv (172.16.3.1) будет при выходе в интернет странслирован в адрес ExtIfIp2(172.16.1.5), и наоборот, всё, что пришло из интернета на этот внешний адрес, улетит на наш сервер. Удобно, когда надо пробросить кучу портов, и в некоторых других случаях. Например для выделенной АТС. В конфигурацию пойдет вот такое правило: binat on $ExtIf from $IntSrv to any -> $ExtIfIp2
NAT Теперь — NAT из локальной сети в Интернет. Синтаксис правила: [ "no" ] "nat" [ "pass" [ "log" [ "(" logopts ")" ] ] ]
[ "on" ifspec ] [ af ] [ protospec ] hosts [ "tag" string ] [ "tagged" string ] [ "->" ( redirhost | "{" redirhost-list "}" ) [ portspec ] [ pooltype ] [ "static-port" ] ] И строка в конфиге: nat on $ExtIf from { $IntIf1Net, $IntIf2Net } to any -> $ExtIfIp1
Это правило говорит о том, что всё, идущее в интернет нужно закрыть первым IP внешнего интерфейса. Можно поставить исключения, подобно binat. Кроме обычной трансляции в один статический IP, можно, например, чтобы PF сам вычислял этот IP с интерфейса. Полезно, если провайдер даёт динамический IP по PPPoE или DHCP: nat on $ExtIf from { $IntIf1Net, $IntIf2Net } to any -> ($ExtIf)
Если на интерфейсе несколько IP, или сеть то её можно указать как напрямую, так и используя такой синтаксис, будет указана вся сеть внешнего интерфейса (поддерживается только round-robin): nat on $ExtIf from { $IntIf1Net, $IntIf2Net } to any -> ($ExtIf:network)
По умолчанию PF будет распределять соответствие соединений и внешний IP по стратегии round-robin. Это поведение можно поменять, используя явное указание сети. Доступны ещё стратегии source-hash, когда он выбирает для каждого адреса IP из получившегося пула, основываясь на внутреннем, либо случайный выбор random. Можно включить прилипание, sticky-address, гарантирующее, что один внутренний IP всегда будет закрываться одним и тем же внешним, пока есть живые соединения. Если живых соединений нет, то адрес отлипает: nat on $ExtIf from { $IntIf1Net, $IntIf2Net } to any -> 172.16.1.0/27 \
source-hash sticky-address RDR Ну и последнее, проброс портов. Отличий мало. [ "no" ] "nat" [ "pass" [ "log" [ "(" logopts ")" ] ] ]
[ "on" ifspec ] [ af ] [ protospec ] hosts [ "tag" string ] [ "tagged" string ] [ "->" ( redirhost | "{" redirhost-list "}" ) [ portspec ] [ pooltype ] [ "static-port" ] ] Правило в конфиг: rdr on $ExtIf inet proto {tcp, udp} from any to $ExtIfIp1 \
port { $torrent_port } -> 172.16.3.15 port $torrent_port Правило завернет входящие пакеты на IP администратора. Из дополнительных возможностей — можно организовать простенький балансировщик: rdr on $ExtIf inet proto {tcp, udp} from any to $ExtIfIp1 \
port { $torrent_port } -> { 172.16.3.15, 172.16.3.15 } \ port $torrent_port round-robin Ну и, как и везде, выше можно поставить исключение. Тэги
Тэг (tag) — это способ пометить пакет, прошедший по правилу, для дальнейшей обработки. Для понимания, в чем волшебство момента, нужно немного разобраться с тем, как пакет проходит по PF. В случае обычного хоста всё просто. Есть интерфейсы, есть входящий на них трафик, есть исходящий, который производит сам хост. Однако в случае маршрутизатора пакет сперва входит на интерфейс, проходит по соответствующим правилам in, вроде: pass in quick on $IntIf1 from $IntIf1Net to $IntIf2Net
затем, перед выходом с другого интерфейса, проходит по правилам out: pass out quick on $IntIf2 from $IntIf1Net to $IntIf2Net
и, если нам нужно просто разрешить ходить между двумя своими локальными сетями, приходится делать четыре правила: pass in quick on $IntIf1 from $IntIf1Net to $IntIf2Net
pass out quick on $IntIf2 from $IntIf1Net to $IntIf2Net pass in quick on $IntIf2 from $IntIf2Net to $IntIf1Net pass out quick on $IntIf1 from $IntIf2Net to $IntIf1Net Есть два варианта избежать этого. Первый — не указывать интерфейсы и направления. Соорудить что-то вроде: pass quick from $IntIf1Net to $IntIf2Net
Но, это не наши методы, потому что снижает "строгость" файрвола. Решение подобной проблемы очень простое: pass in quick on $IntIf1 from $IntIf1Net to $IntIf2Net tag PASS
pass in quick on $IntIf2 from $IntIf2Net to $IntIf1Net tag PASS pass out tagged PASS Тэг, сохраняясь на всём пути прохождения пакета, в конце концов попадёт на правило pass out, и трафик пройдёт. Такой приём позволяет сократить количество правил и выстроить более логичную и простую их структуру. Точно так же можно, к примеру, блокировать трафик на части интерфейсов. А еще правила фильтрации PF, в случае, если на интерфейсе есть трансляция, увидят уже странслированные пакеты. В результате на исходящем интерфейсе не всегда можно однозначно понять, откуда пришел пакет. К примеру правило, разрешающее торрент администратора, на внешнем интерфейсе, будет использовать локальный IP: pass in on $ExtIf proto { tcp, udp } from any to 172.16.3.15 \
port { $torrent_port } tag PASS Если собрать всё в кучу, то, на данный момент, получится следующееSPL######## macros section ########
ExtIf="re0" # внешний интерфейс IntIf1="em0" # локальный 0, бухгалтерия IntIf2="em1" # локальный 1, всё остальное. ExtIfIp1="172.16.1.1" # Внешний IP адрес ExtIfIp2="172.16.1.5" # Дополнительный адрес от провайдера IntIf1Ip="172.16.2.254" # IP локального 0 IntIf1Net="172.16.2.0/24" IntIf2Ip="172.16.3.254" # IP локального 1 IntIf2Net="172.16.3.0/24" IntSrv="172.16.3.1" ExtSrv="172.16.1.2" torrent_port="59715" permit_tcp_ports="22,53" permit_udp_ports="53,123" web_ports = "http,https" permit_corp_ports ="http,https" permit_add_tcp_ports = "8080,8443" ######## table section ######## table <privileged_If1> { 172.16.2.2 } # главбух и избранные из бухгалтерии table <privileged_If2> { 172.16.3.15, 172.16.3.125 } # избранные из общей сети table <bad_users> persist # табличка для тех, кто нам не нравится # хосты, которые нам просто не нравятся, находятся тут table <block_list> file "/etc/pf.blocklist.conf" # корпоративные ресурсы, доступ по hppt(s) table <corp_res> file "/etc/pf.corpres.conf" table <sites_for_all> file "/etc/pf.sitesforall.conf" # сайты, доступные всем table <bad_sites> file "/etc/pf.badsites.conf" # Брутфорсеры ssh. если таблица пустая, PF её удалит. Для отмены такого поведения используется ключевое слово persist table <block_ssh> persist # заблокированный доступ до веб до сервера table <block_web> persist ######## options section ######## # разрываем соединения с ответом, а не просто дропаем пакеты set block-policy return # пропускаем проверку на локальной петле, там фильтрация не нужна set skip on lo0 #scrub section # нормализация всего входящего трафика scrub in all #Queueing section # в данный момент пустая ######## nat section ######## #статическая трансляция для сервера binat on $ExtIf from $IntSrv to any -> $ExtIfIp2 #NAT для клиентов nat pass on $ExtIf from { $IntIf1Net, $IntIf2Net } to any -> $ExtIfIp1 # прооброс портов на машину администратора rdr on $ExtIf inet proto {tcp, udp} from any to $ExtIfIp1 port { $torrent_port } -> 172.16.3.15 port $torrent_port rdr on $ExtIf inet proto {tcp, udp} from any to $ExtIfIp1 \ port { $torrent_port } -> { 172.16.3.15, 172.16.3.15 } port $torrent_port round-robin ######## filtering section ######## # запрет всего по умолчанию, помним, что это не означает окончание обработки пакета. block log all ## Разрешения для входящих пакетов из Интернет. ## # разрешаем ssh с защитой от брутфорса block in quick proto tcp from <block_ssh> port 22 pass in quick on $ExtIf proto tcp to { $ExtIfIp1 $IntSrv } port { 22 } \ keep state (max-src-conn 10, max-src-conn-rate 3/10, \ overload <block_ssh> flush) tag PASS # разрешаем Web с защитой от ботов и прочего block in quick on $ExtIf from <block_web> pass in on $ExtIf proto tcp to $IntSrv port { $web_ports } \ synproxy state (max-src-conn 100, max-src-conn-rate 20/1, \ overload <block_web> flush global) tag PASS # разрешаем ходить торрентам pass in on $ExtIf proto { tcp, udp } from any to 172.16.3.15 port { $torrent_port } tag PASS ## Разрешения для внутренних сетей ## # разрешаем серверу ходить до корпоративных ресурсов pass in quick on $IntIf2 proto tcp from $ExtIfIp2 to $ExtSrv port { $web_ports, $permit_corp_ports, $permit_add_tcp_ports } tag PASS # Если надо разрешить ему ходить в интернет, то раскомментируем # pass in quick on $IntIf2 from $IntSrv to any tag PASS # разрешаем ходить между локалками всем pass in quick on $IntIf1 from $IntIf1Net to $IntIf2Net tag PASS pass in quick on $IntIf2 from $IntIf2Net to $IntIf1Net tag PASS # разрешаем всё привилегированным пользователям pass in on $IntIf1 from <privileged_If1> to any tag PASS pass in on $IntIf2 from <privileged_If2> to any tag PASS # разрешаем ДНС, icmp всем pass in quick on $IntIf1 proto tcp from ($IntIf1:network) to any port { $permit_tcp_ports } tag PASS pass in quick on $IntIf2 proto tcp from ($IntIf2:network) to any port { $permit_tcp_ports } tag PASS # разрешаем всем корпоративные ресурсы pass in quick on $IntIf1 proto tcp from ($IntIf1:network) to $ExtSrv port { $web_ports } tag PASS pass in quick on $IntIf2 proto tcp from ($IntIf2:network) to $ExtSrv port { $web_ports } tag PASS pass in quick on $IntIf1 from ($IntIf1:network) to <sites_for_all> tag PASS pass in quick on $IntIf2 from { $IntIf2Net } to <sites_for_all> tag PASS block in quick from <bad_users> to any block in quick from { $IntIf1Net, $IntIf2Net } to <bad_sites> pass in quick from { $IntIf1Net,$IntIf2Net } to any tag PASS ## разрешаем исходящий трафик ## pass out log tagged PASS pass out on { $IntIf1,$IntIf2 } # разрешаем самому хосту ходить на некоторые порты pass out quick on $ExtIf proto tcp from ($ExtIf) to any port { $permit_tcp_ports } pass out quick on $ExtIf proto udp from ($ExtIf) to any port { $permit_udp_ports } Вполне рабочий конфигурационный файл PF, который сделает всё, что нужно. Однако можно сделать еще лучше. Якоря Так же известные как anchors. Это отдельные наборы правил PF. Основные свойства:
Есть несколько способов определения якорей:
=========== Источник: habr.com =========== Похожие новости:
Блог компании Интернет Контроль Сервер ), #_informatsionnaja_bezopasnost ( Информационная безопасность ), #_sistemnoe_administrirovanie ( Системное администрирование ), #_itinfrastruktura ( IT-инфраструктура ), #_soft ( Софт ) |
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 12:37
Часовой пояс: UTC + 5