Pull to refresh
0
Интернет Контроль Сервер
Универсальный инструмент системного администратора

FreeBSD. Трансляции, тэги и якоря в PF

Reading time15 min
Views5.6K
  1. Файрвол PF в ОС FreeBSD
  2. FreeBSD. Фильтрация трафика PF
  3. FreeBSD. Трансляции, тэги и якоря в PF <- Вы здесь
  4. FreeBSD. Условная маршрутизация средствами PF
  5. FreeBSD. Путь сетевого пакета внутри ядра

Введение


В прошлых статьях мы разобрали, что такое 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"

Затем активируем маршрутизацию


# sysctl net.inet.ip.forwarding=1

Либо перезагружаем машину.


Всё, маршрутизация уже работает.


Добавляем макросов, таблиц, скраб, опции, очереди (которых нет)
#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

Если собрать всё в кучу, то, на данный момент, получится следующее
######## 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 NAME исполнит правила nat
  • rdr-anchor NAME исполнит правила rdr
  • binat-anchor NAME исполнит правила binat
  • anchor NAME исполнит правила фильтрации
  • load anchor NAME from FILE команда загрузки из файла

Во время определения 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

Теперь можно удалить эти правила из конфигурации, оставив только anchor, а остальные, относящиеся к другому интерфейсу, определить в якоре по месту
######## 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 пользователей.

Tags:
Hubs:
Total votes 6: ↑6 and ↓0+6
Comments7

Articles

Information

Website
xserver.a-real.ru
Registered
Founded
Employees
11–30 employees
Location
Россия