PF (Packet Filter)

Материал из Национальной библиотеки им. Н. Э. Баумана
Последнее изменение этой страницы: 14:35, 17 января 2018.
Packet Filter (PF)
Packet Filter.png
Разработчики: проект OpenBSD
Постоянный выпуск: 4.8 / 1 ноября 2010 года
Написана на: C
Операционная система: BSD-системы
Тип ПО: Межсетевой экран
Лицензия: BSD
Веб-сайт PF FAQ

Packet Filter (PF) — файрвол, разрабатываемый в рамках проекта OpenBSD. Обладает высокой скоростью работы, удобством в конфигурировании и большими возможностями, включая поддержку IPv6. На данный момент используется, помимо OpenBSD, в NetBSD и FreeBSD, а также основанных на этих трёх MirOS BSD, DesktopBSD, pfSense и других. Начиная с версии 10.7 PF используется в Mac OS X. PF был портирован на Microsoft Windows и лёг в основу файрвола Core Force[1].

История

История PF началась в 2000 году, когда Даррен Рид, разработчик использовавшегося в то время в OpenBSD файрвола IPFilter, изменил лицензию на него. Тогда ipf был исключён из CVS-репозитория, а его место к релизу OpenBSD 3.0 занял написанный «с нуля» PF.

В OpenBSD 3.3 появился pfsync — псевдоинтерфейс, позволяющий реплицировать информацию о контексте соединений между двумя (а позднее и больше) хостами. При использовании CARP или другой аналогичной технологии pfsync позволяет, в частности, создавать отказоустойчивые конфигурации из нескольких физических межсетевых экранов: при отказе одного хоста второй продолжит обрабатывать сетевой трафик без разрыва соединений.

Изначально PF был довольно похож на IPFilter. Крупный редизайн внутренней архитектуры начался в 2005 году[2] усилиями Хеннинга Брауэра и Райана Макбрайда. В рамках этого проекта PF получил поддержку нового вида правил match, новую схему учёта контекста соединений (англ. states в оригинальной терминологии). Так же крупным изменением стал отказ от разделения наборов правил по типам: ранее PF, как и IPFilter, имел раздельные наборы правил для NAT и фильтрации трафика. Так же, в рамках общего развития OpenBSD, PF получил поддержку множественных таблиц и доменов маршрутизации.

Архитектура

PF состоит из двух частей: собственно фильтра пакетов[3] и утилиты pfctl,[4] которая предоставляет интерфейс для управления межсетевым экраном. Фильтр полностью работает в контексте ядра операционной системы, взаимодействие с ним осуществляется через системный вызов ioctl.[5] Поэтому pfctl, строго говоря, не является необходимой частью PF.

PF изначально не рассчитан на многопоточную обработку пакетов. С другой стороны, отсутствие блокировок положительно влияет на производительность. Фильтр обрабатывает сетевые пакеты один (при посылке пакета с того же компьютера, на котором стоит фильтр, на другой компьютер, или наоборот) или два (при пересылке внутри компьютера или когда компьютер с фильтром исполняет роль сетевого шлюза) цикла обработки.

Оптимизация

PF умеет пропускать ненужные проверки во время прохождения списка правил. Например, если два правила подряд относятся только к протоколу TCP, то пакет любого другого протокола (например, UDP), после того как не подойдёт к первому правилу, не будет проверяться на втором. Для этого сначала при составлении набора правил pfctl, зная наиболее оптимальный порядок проверок, может изменить взаимный порядок нескольких идущих подряд правил; затем подготовленный набор анализируется при загрузке в PF и для каждого правила составляется карта переходов по несовпадению того или иного параметра.

PF при оптимизации списка правил может также учитывать накопившуюся статистику частоты проверок для правил, и корректировать карту переходов в соответствии с этой статистикой.

Порядок работы

Фильтр обрабатывает сетевые пакеты в один (при посылке пакета с того же компьютера, на котором стоит фильтр, на другой компьютер, или наоборот) или два (при пересылке внутри компьютера или когда компьютер с фильтром исполняет роль сетевого шлюза) цикла обработки.

Собственно обработка пакета происходит согласно набору правил. В финале обработки пакет либо отбрасывается, либо пропускается. Каждое правило состоит из набора условий и набора указаний, выполняемых при удовлетворении набора условий. Правила бывают трёх видов:

match
Если пакет удовлетворяет условиям правила, то указания из данного правила выполняются моментально. match-правила обычно используются для NAT, журналирования трафика, QoS и так далее.
block
Если пакет не удовлетворяет условиям правила, то он помечается как подлежащий блокировке. PF позволяет как просто отбросить пакет, так и сгенерировать ICMP-сообщение об ошибке.
pass
Если пакет удовлетворяет условиям правила, то он помечается как подлежащий пропуску далее.

Указания, записанные для block- и pass-правил, выполняются после завершения прохода по набору правил. Если для block- или pass-правила сделана соответствующая пометка, то при удовлетворении пакетом условий данного правила, проход по набору правил будет прерван с выполнением соответствующих указаний. Такой порядок позволяет задать серию правил, постепенно сужающих область применения, что выглядит более естественно, чем обратный порядок. Если ни одно block- или pass-правило не подошло, то пакет пропускается: это мера защиты от случайной ошибки при конфигурировании сетевого экрана.

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

нормализация
сборка фрагментированных и отбрасывание заведомо некорректных пакетов, а также другие операции, упрощающие дальнейшую обработку;
трансляция
перенаправление трафика на уровнях 2 (более тонкое, чем его могут обеспечить обычные средства маршрутизации) и 3 модели OSI, с поддержкой NAT и пулов адресов назначения;
приоритизация
принудительное выставление типа обслуживания пакета, помещение пакета в ту или иную очередь ALTQ;
фильтрация
принятие окончательного решения о пропуске или блокировке сетевого пакета. Также при фильтрации PF просматривает все правила, и затем применяет последнее подошедшее правило. Это удобно, так как позволяет задать серию правил, постепенно сужающих область применения, что выглядит более естественно, чем обратный порядок. Если ни одно правило не подошло, то пакет пропускается; эта мера служит защитой от случайной ошибки при конфигурировании сетевого экрана. Однако для правил фильтрации можно сделать соответствующую пометку, и тогда PF, если данное правило подходит, сразу закончит обработку пакета. Следует отметить, что при задании правил трансляции можно указать безусловный пропуск трафика; в таком случае фаза фильтрации опускается, что позволяет повысить производительность. И наоборот, при фильтрации можно указать шлюз, на который должен быть перенаправлен пакет; это бывает полезно в тех случаях, когда нужно задействовать параметры фильтрации, недоступные при трансляции.

При трансляции PF просматривает правила до первого подходящего в следующем порядке:

  • Правила binat (двусторонняя трансляция)
  • Правила rdr (перенаправление) и nat (односторонняя трансляция)

Если подошедшее правило содержит соответствующую пометку, то до этапа фильтрации дело не доходит и пакет сразу отправляется по назначению.


Возможности фильтрации

PF умеет фильтровать пакеты по следующим параметрам:

  • Сетевой адрес (для TCP и UDP также и порт) источника и получателя пакета
  • Сетевой интерфейс (или их группа), на котором обрабатывается пакет, а также на котором он изначально появился в системе
  • Корректность маршрута, с которого пришёл пакет (да или нет)
  • Флаги (для TCP)
  • Биты типа обслуживания (ToS)
  • Тип и код ICMP (для ICMP и ICMPv6)
  • Теги пакетов
  • Локальный пользователь (владелец сокета)
  • Различные счётчики соединений
  • Вероятность

Последний параметр позволяет создавать правила, которые срабатывают «иногда», что помогает бороться с (порой непреднамеренными) DDoS-атаками.

Теги назначаются правилами PF. У каждого пакета может быть не более одного тега. Правилом можно установить/заменить тег, но нельзя убрать существующий. Тег сохраняется у пакета на всё время прохождения по сетевому стеку.

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

Для правил можно указывать метки. Одна и та же метка может соответствовать нескольким правилам. Метки позволяют лучше идентифицировать правила из пользовательского пространства, а также отключать встроенную оптимизацию набора правил для определённых правил; последнее может быть нужно, например, для биллинговых систем.

PF не только умеет проводить фильтрацию с учётом контекста, но поддерживает три варианта работы в этом режиме (терминология из оригинальной документации):

keep state
простой режим, запоминается только соответствие пар сетевых адресов и портов; этот режим применим не только к TCP, но и к UDP.
modulate state
более сложный режим, в котором PF самостоятельно выбирает начальные значения счётчиков пакетов TCP; это обеспечивает улучшенную защиту в случаях, когда одна из сторон выбирает плохие с точки зрения вероятности угадывания значения этих счётчиков.
synproxy state
в этом режиме PF самостоятельно устанавливает TCP-соединение с другой стороной, и только после этого соответствующие пакеты отсылаются инициатору; это обеспечивает защиту от атак типа SYN-флуд с подделкой адреса отправителя.

По умолчанию все pass-правила учитывают контекст (keep state), а относящиеся к TCP ещё и проверяют флаги SYN-пакета. Это сделано поскольку позволяет заметно сократить объём правил (как в плане их количества, так и в плане их описания в файле конфигурации) в типичных ситуациях. При этом можно принудительно отказаться от этих возможностей для конкретного правила или всего их набора. Следует также учитывать, что если пакет не попал ни под одно pass-правило, то никаких проверок и создания контекста не происходит.

Настройка

Существуют два варианта запуска:

1. Пересборка ядра.

2. Инициализация через pf.conf.

В любом из двух этих случаев предполагается, что в конфигурации ядра системы содержаться строки: options INET, device bpf.

1. Пересборка ядра.

Включение PF путем компиляции с ядром FreeBSD не является обязательным требованием. При компиляции PF с ядром загружаемый модуль не используется. Для инициализации PF необходимо добавить в файл конфигурации ядра следующие строки:

device pf  #включает поддержку межсетевого экрана ''Packet Filter''
device pflog   #включает необязательное сетевое псевдоустройство pflog, которое может использоваться для протоколирования трафика
device pfsync  #включает необязательное сетевое псевдоустройство pfsync, используемое для отслеживания ''изменений состояния'' 

Стоит отметить, что pfsync не входит в загружаемый модуль, и для его использования необходимо собрать новое ядро.

2. Инициализация через pf.conf

Для активации PF в /etc/rc.conf должны быть включены следующие переменные:

pf_enable="YES"                     # Включить PF (загрузить модуль, если необходимо)
pf_rules="/etc/pf.conf"             # определение правил для pf
pf_flags=""                          # дополнительные флаги для запуска pfctl 
pflog_enable="YES"                   # запустить pflogd
pflog_logfile="/var/log/pflog"      # где pflogd должен сохранять протокол
pflog_flags=""                      # дополнительные флаги для запуска pflogd 

Если за межсетевым экраном находится локальная сеть и необходимо передавать пакеты для компьютеров этой сети, или использовать NAT, необходимо включить также следующий параметр:

 gateway_enable="YES"            # Включить сетевой шлюз 

После инициализации управление осуществляется с помощью следующих команд:

pfctl -e                # включить PF
pfctl -f  <имя_файла>     # загрузить правила из конфигурационного файла  <имя_файла> (обычно /etc/pf.conf)
pfctl -nf <имя_файла>    # анализировать конфигурационный файл <имя_файла>, но не загружать
pfctl -Nf <имя_файла>    # загрузить только правила NAT из файла
pfctl -Rf <имя_файла>    # загрузить только правила фильтрации
pfctl -sn                # показать текущие правила NAT
pfctl -sr                 # показать текущие правила фильтрации
pfctl -ss                # показать текущее состояние таблиц
pfctl -si                # показать статистику правил и состояние счетчиков
pfctl -sa               # показать все 

Конфигурационный файл (/etc/pf.conf) состоит из следующих частей:

  • Макросы: Определяемые пользователем переменные, которые могут содержать адреса IP, имена интерфейсов, и т.д.
  • Таблицы: Применяются для хранения списков IP адресов.
  • Опции: Параметры, влияющие на работу pf.
  • Scrub: Подготовка пакета к нормализации и дефрагментации.
  • Очереди: Обеспечивает управление полосой пропускания и установку приоритетов пакета.
  • Трансляции: Контроль NAT и перенаправлением пакета.
  • Правила фильтрации: Осуществляют выборочную фильтрацию пакетов на интерфейсах.

За исключением макросов и таблиц порядок следования разделов в файле должен быть таким же, но допускается отсутствие некоторых пунктов. Пустые строки игнорируются, и строки начинающийся с # считаются комментарием. Списки позволяют определять множества, имеющие общие признаки в пределах правила - такие как IP адреса, номера портов и т.д. При загрузке наборов правило для списка "раскладывается" на отдельные правила для каждого элемента. Синтаксис: {элементы_списка} Стоит отметить, что запятая при перечислении элементов необязательна, достаточно пробела.

Макросы

Макросы - определяемые пользователем переменные, которые могут представлять собой IP адреса, номера портов, имена интерфейсов, и т.д. Имена макросов должны начаться с символа и могут содержать символы,цифры, и символы подчеркивания. Названия макросов не могут носить имена зарезервированных слов, типа pass, out, или queue. Синтаксис:

 <имя_макроса>="<значение>" # определение макроса 
$<имя_макроса>             # вызов макроса

<значением> могут быть также списки и другие макросы, возможна рекурсия:

<имя_макроса_списка>="{" <имя_макроса1><имя_макроса2> "}"

Таблицы адресов

Одной из самых интересных возможностей PF является работа с таблицами адресов:

  • Таблицы могут содержать как IPv4-, так и IPv6-адреса, вместе с маской подсети для каждого;
  • Записи в таблице могут быть быть помечены как исключение, что позволяет кратко описывать сложную топологию (см. ниже);
  • Поиск по таблице происходит быстрее, чем линейный поиск по набору адресов (и заметно быстрее, чем перебор правил, различающихся лишь адресами в одном и том же параметре);
  • Таблицы могут быть произвольным образом изменены без необходимости перезагружать правила;
  • По каждой записи в таблице может вестись статистика;
  • Посредством опции фильтрации overload в выбранную таблицу могут помещаться адреса, превышающие те или иные ограничения на количество соединений;
  • Записи в таблицах могут быть автоматически удалены по достижении указанного времени их существования.

Например, в таблицу можно занести все приватные адреса[6][7][8] в единую таблицу и затем блокировать попытки подключения извне от якобы этих адресов всего одним правилом.

Более того, путём использования пометок об исключении адресов (диапазонов адресов) можно путём всего трёх записей в таблице указать такую конфигурацию: в таблицу входит диапазон 10.0.0.0/8, кроме 10.0.3.192/26, плюс ещё входит 10.0.3.211. Соответствующие записи в таблицу можно заносить в любом порядке, PF будет их использовать в соответствии с их префиксами (маской подсети).

Сторонние программы через системный вызов ioctl или посредством вызова программы pfctl могут управлять содержимым таблиц. Например, DHCP-сервер dhcpd из состава OpenBSD поддерживает использование до трёх таблиц PF:

  • таблица, в которую добавляются IP-адреса новых DHCP-клиентов
  • таблица, из которой удаляются освобождающиеся IP-адреса
  • таблица, в которой поддерживается список временно запрещённых к использованию IP-адресов

Управление таблицами также может осуществляться на лету, используя pfctl

pfctl -t <имя_таблицы> -T add     # добавить в таблицу
pfctl -t <имя_таблицы> -T delete # удалить
pfctl -t <имя_таблицы> -T show   # вывести на экран ip адреса из таблицы Это также откроет таблицу, если она не существует.

Блоки правил

Правила можно объединять в блоки (anchors в оригинальной документации). При этом можно для каждого блока задавать общие параметры, которые будут действовать для всех правил в блоке.

Блоки обрабатываются наравне с правилами и могут вкладываться друг в друга. При этом содержимое блоков может изменяться независимо друг от друга, а также от общего списка правил. Последний, по сути, является тем же блоком.

Блоки правил удобны для использования в программах, так или иначе управляющих потоками трафика. Примеры программ:

  • relayd, прокси-сервер для организации автоматического контроля списка работающих backend-серверов;
  • authpf, командная оболочка UNIX, позволяющая контролировать доступ к сетевым ресурсам при помощи аутентификации пользователей через SSH.

Использование Packet Filter

В данном видео показана работа по блокировке определенных пакетов с использованием PF

Литература

Примечания

  1. Сетевой экран Core Force для Microsoft Windows 2000/XP
  2. Henning Brauer. "«Placeholder: something OpenBSD related» (слайд 6)". Archived from the original on 2012-02-14. 
  3. страница руководства pf(4)
  4. страница руководства pfctl(8)
  5. страница руководства ioctl(2)
  6. RFC 1918 (приватные адреса в Интернет)
  7. RFC 3927 (адреса для Zeroconf)
  8. IP Filter HOWTO, содержит хороший список приватных адресов с пояснениями

Ссылки