Введение


В Рунете есть множество статей о настройке FreeBSD и PF, но все они разрозненны и несистематичны. А за любыми более-менее интересными вещами, такими, как маршрутизация средствами файрвола (Policy Based Routing), приходится читать оригинальную документацию, например, OpenBSD PF FAQ. Однако, есть отличия в синтаксисе команд для FreeBSD и OpenBSD. В этом цикле статей мы пробуем систематизировать и разобрать возможности PF от простого к сложному. Наверняка, эта вводная статья будет похожа на все остальные статьи о Packet Filter. Поэтому тем, кто уже знаком с базовыми возможностями, будет не интересно. Однако, без вступления не обойтись, а мясо будет в следующих статьях.


PFPacket Filter — это межсетевой экран, изначально созданный в рамках проекта OpenBSD. В 2003 году был портирован во FreeBSD. В 2004 году был интегрирован в основную систему. Основные возможности:

  • Фильтрация на основе адресов, портов, протоколов, интерфейсов
  • NAT — Source NAT, подмена адреса отправителя. Destination nat, подмена адреса получателя, проброс порта
  • Scrub — нормализация сетевого трафика. Помогает от некоторых видов dos атак, основанных на формировании специально подготовленных пакетов
  • SYN-proxy — Защита от SYN-flood атак
  • Балансировка соединений
  • Отказоустойчивость — pfcync позволяет синхронизировать состояние файрволов на нескольних хостах, что, в сочетании с протоколом CARP, позволяет создать отказоустойчивый файрвол, который продолжит обрабатывать соединения после падения активной ноды
  • Прозрачный файрвол (Без собственного IP-адреса, включая фильтр 2 уровня)
  • Макросы — аналог переменных
  • Таблицы — динамически изменяемые без перезагрузки конфигурации списки IP адресов
  • Метки — позволяет метить пакеты, если простой фильтрации недостаточно
  • Якоря (anchors) — наборы правил, похожи на таблицы IPTables в Linux
  • Сбор статистики и вывод графиков с помощью утилиты pfstat
  • Автоматическая оптимизация правил при загрузке

Основное отличие от того же IPTables — непривычная схема работы. Обработка пакета не заканчивается после первого совпадения с правилом. То есть, если вы поставили первым правилом «запретить всё», то пакет не будет отброшен, а пометится как запрещенный, пойдёт дальше по правилам, и, если его не разрешит никакое правило, то будет отброшен. Это важно понимать и использовать. Однако, если нужно, это поведение можно отменить параметром quick в правиле.

Управление и полезные команды


Для включения PF достаточно в файле «/etc/rc.conf» указать опции:

pf_enable="YES" # включает pf и загружает модуль
pf_flags="" # дополнительные флаги pfctl
pf_rules="/etc/pf.conf"  # файл конфигурации
pflog_enable="YES" # запуск pflog
pflog_flags="" # флаги pflog
pflog_logfile="/var/log/pflog" # файл лога

Основные команды управления файрволом:

pfctl - # Включить файрвол
pfctl -d # Выключить файрвол
pfctl -nf # Проверить синтаксис файла
pfctl -f # Перечитать правила из файла
pfctl -Rf # Перечитать правила фильтрации из файла
pfctl -Nf # Перечитать правила NAT из файла
pfctl -sa # Просмотр всех состояний
pfctl -s # Просмотр правил фильтрации
pfctl -sn # Просмотр правил NAT
pfctl -s Anchors -v # Просмотр дерева якорей
pfctl -ss # Просмотр текущих соединений

Структура файла конфигурации и базовые настройки


Файл конфигурации состоит из разделов:

  1. Макросы
  2. Таблицы
  3. Опции
  4. Правила нормализации трафика (scrub)
  5. Очереди, приоритезация и контроль скорости
  6. NAT трансляции адресов
  7. Фильтрация пакетов

Правила в общем случае имеют следующий синтаксис:

action [direction] [log] [quick] [on interface] [af] [proto protocol]
          [from src_addr [port src_port]] [to dst_addr [port dst_port]]
          [flags tcp_flags] [state]

action — что следует сделать с пакетом
direction — in out, направление
log — попадёт ли пакет в pflog
quick — если пакет попал под это правило, то дальнейшей обработки не будет. Это правило будет последним для пакета
interface — название сетевого интерфейса
af — address family, inet или inet6, IPv4 или IPv6 соответственно
protocol — протокол 4 уровня, к примеру: tcp, udp, icmp
scr_addr, dst_addr — адреса источника и назначения
src_port, dst_port — порты
tcp_flags — флаги tcp
state — опции сохранения состояния. Например, keep state будет означать, что соединение сохранится в таблице состояний, и ответные пакеты могут проходить. Поведение по умолчанию.

Возьмем простейший веб-сервер в вакууме. Необходимо открыть входящие соединения по портам tcp 22, 80, 443 (ssh, http, https). Также нужно открыть исходящие соединения по портам tcp 22, 80, 443 (ssh, http, https) и udp 53, 123 (dns и ntp). Всё остальное запретить.

# ee pf.conf

#macros section
permit_tcp_ports="22,80,443"
permit_udp_ports="53,123"

#table section
# в данный момент пустая

#options section
set block-policy return # разрываем соединения с ответом, а не просто дропаем пакеты
set skip on lo0 # пропускаем проверку на локальной петле, там фильтрация не нужна

#scrub section
scrub in all # нормализация всего входящего трафика

#Queueing section
# в данный момент пустая

#nat section
# пустая, у нас нечего транслировать


#filtering section
block all # запрет всего по умолчанию, помним, что это не означает окончание обработки пакета.
pass in proto tcp to port { $permit_tcp_ports } # разрешаем входящие соединения
pass out proto tcp to port { $permit_tcp_ports } # разрешаем исходящие соединения tcp
pass out proto udp to port { $permit_udp_ports } # разрешаем исходящие соединения udp
pass out inet proto icmp # разрешаем исходящий icmp

Затем вводим команду проверки синтаксиса:
pfctl -nf pf.conf

Если сообщений об ошибках нет, вводим команду применения правил:
pfctl -f pf.conf

Для проверки посмотрим правила фильтрации:

# pfctl -sr 
scrub in all fragment reassemble 
block return all 
pass out proto tcp from any to any port = ssh flags S/SA keep state 
pass out proto tcp from any to any port = http flags S/SA keep state 
pass out proto tcp from any to any port = https flags S/SA keep state 
pass out proto udp from any to any port = domain keep state 
pass out proto udp from any to any port = ntp keep state 
pass out inet proto icmp all keep state 
pass in proto tcp from any to any port = ssh flags S/SA keep state 
pass in proto tcp from any to any port = http flags S/SA keep state 
pass in proto tcp from any to any port = https flags S/SA keep state 

Как видно, макросы развернулись в отдельные правила по каждому порту, порядок изменен автоматически. В остальном всё так, как нужно.

Итог


Мы разобрались, что такое Packet Filter, узнали его основные возможности. Разобрались в структуре конфигурации PF и её основных секциях. Создали самую простую конфигурацию, которая, однако вполне функциональна, включает макросы, нормализацию пакетов и фильтрацию входящих и исходящих пакетов. В следующей статье разберем более подробно правила фильтрации, управление состояниями и флаги.

Наше решение, Интернет Контроль Сервер – это шлюз безопасности, построенный на базе FreeBSD. Данная система была выбрана ввиду своей стабильности, скорости сетевого стэка, встроенной в ядро поддержки ZFS и отсутствия заморочек с лицензиями. Кроме того, работа с FreeBSD достаточно приятна, хоть и не во всем проста. Но мы будем рады делиться с вами этим опытом!