OpenBSD : PF: Пакетный фильтр OpenBSD

1. Начальная конфигурация
         + PF: Начало
         + Списки и макросы
         + Таблицы
         + Фильтрация пакетов
         + NAT
         + Перенаправление трафика
         + Шаблоны для создания наборов правил

PF: Начало
----------


Активация:

Для активизации и чтения правил конфигурации pf при начальной  загрузке, необходимо в [6]/etc/rc.conf прописать следующее:

pf=YES


Для вступления изменений в силу, необходимо перезагрузить систему.  Активизировать и остановить pf можно используя программу pfctl(8):

# pfctl-e
# pfctl-d


для запуска и останова соответственно. Обратите внимание, что загрузка правил при этом не производится, их необходимо подгружать отдельно, до или после запуска pf.


Конфигурация:

  pf читает правила конфигурации из файла [7]/etc/pf.conf во время
  загрузки, когда выполняются [8]rc.scripts. Обратите внимание, что
  /etc/pf.conf - название по умолчанию и он представляет собой просто
  текстовый файл, содержащий наборы правил, загружаемые и
  интерпретируемые pfctl(8) и вставляемые в pf(4). Для некоторых
  приложений наборы правил могут располагаться в других файлах и
  подгружаться после загрузки системы. Как и другие приложения UNIX, pf
  обладает большой гибкостью.

  Файл pf.conf состоит из семи частей:

   1. Макросы: Определяемые пользователем переменные, которые могут
      содержать адреса IP, имена интерфейсов, и т.д.

   2. Таблицы: Применяются для хранения списков IP адресов

   3. Опции: Параметры, влияющие на работу pf

   4. Scrub: Подготовка пакета к нормализации и дефрагментации

   5. Очереди: Обеспечивает управление полосой пропускания и
      установку приоритетов пакета.

   6. Трансляции: Контроль NAT и перенаправлением пакета

   7. Правила фильтрации: Осуществляют выборочную фильтрацию пакетов
      на интерфейсах

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

  Пустые строки игнорируются, и строки начинающийся с # считаются
  комментарием.


Управление:

  После начальной загрузки управление pf может осуществляться через
  программу pfctl(8). Вот несколько примеров:

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

  Для полного списка команд смотрите man pfctl(8).


Списки и макросы
----------------

Списки:

  Списки позволяют определять множества, имеющие общие признаки в
  пределах правила - такие как IP адреса, номера портов и т.д. Таким
  образом, вместо прописывания нескольких правил фильтрации для каждого
  IP адреса, который должен быть заблокирован, мы можем определить
  список IP адресов в пределах одного правила. Списки должны находиться
  внутри скобок {}.

  Когда pfctl(8) доходит до списка при загрузке наборов правил, он
  раскладывает их на отдельные правила, для каждого элемента списка. Для
  примера:

       block out on fxp0 from { 192.168.0.1, 10.5.32.6 } to any

  Будет преобразован в:

       block out on fxp0 from 192.168.0.1 to any
       block out on fxp0 from 10.5.32.6 to any

  Множественные списки могут применяться не только для блокировки:

       rdr on fxp0 proto tcp from any to any port { 22 80 } -> 192.168.0.6
       block out on fxp0 proto { tcp udp } from { 192.168.0.1, 10.5.32.6 } to any port { ssh telnet }

  Стоит отметить, что запятая в списке является необязательной.


Макросы:

  Макросы - определяемые пользователем переменные, которые могут держать
  IP адреса, номера портов, имена интерфейсов, и т.д. Макросы позволят
  облегчить написание наборов правил и сделают поддержание набора правил
  несравненно легче.

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

       ext_if = "fxp0"
       block in on $ext_if from any to an

  Это создаст макрос с именем ext_if. При использовании макроса, его
  имени должен предшествовать знак $.
  Макросы также могут быть расширены до списков.

       friends = "{ 192.168.1.1, 10.0.2.5, 192.168.43.53 }"

  Макросы могут определяться рекурсивно. В этом случае должен
  использоваться следующий синтаксис:

       host1 = "192.168.1.1"
       host2 = "192.168.1.2"
       all_hosts = "{" $host1 $host2 "}"

  Теперь макрос $all_hosts расширен до значений 192.168.1.1, 192.168.1.2.



Таблицы
--------


Введение:

  Таблицы используются для хранения группы адресов IPv6 и/или IPv4.
  Поиски в таблице занимают гораздо меньше времени и потребляют меньше
  ресурсов, чем списки. По этой причине, таблица идеальна чтобы хранить
  большую группу адресов, поскольку время поиска в таблице, содержащей
  50 000 адресов - не намного больше чем для 50 адресов. Таблицы могут
  использоваться следующими способами:

    * источник и/или адрес назначения для filter, scrub, NAT, и
      redirection rules
    * адрес трансляции для правил NAT
    * адрес переназначения для правил редиректа
    * адрес назначения для правил фильтрации route-to, reply-to, и
      dup-to

  Таблицы определяются в pf.conf или с помощью pfctl(8).


Конфигурация:

  В pf.conf таблицы создаются используя директиву table. Следующие
  атрибуты могут быть определены для каждой таблицы:

    * const - содержание таблицы не может быть изменено после ее
      создания. Когда этот атрибут не определен, pfctl(8) может
      использоваться, чтобы добавлять или удалять адреса из таблицы в
      любое время, при выполнении с securelevel(7), равным двум и выше.

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

  Пример:

       table { 192.0.2.0/24 }
       table const { 192.168.0.0/16, 172.16.0.0/12, 10.0.0.0/8 }
       table persist

       block in on fxp0 from { ,  } to any
       pass  in on fxp0 from to any

  Адреса могут также быть определены, используя модификатор типа
  отрицание (или "не"):

       table { 192.0.2.0/24, !192.0.2.5 }

  Таблица goodguys теперь содержит адреса сети 192.0.2.0/24, за
  исключением адреса 192.0.2.5.
  Обратите внимание, что имена таблицы всегда включаются в <>.

  Таблицы могут также могут заполняться из файлов, содержащих список
  адресов IP и сетей:

       table  persist file "/etc/spammers"
       block in on fxp0 from  to any

  Файл/etc/spammers содержал бы список IP адресов или сетей CIDR. Любая
  строка начинающаяся с #, будет обработана как комментарий и
  проигнорирована.


Управление с помощью pfctl:

  Таблицы могут управляться на лету, используя pfctl(8). Например, для
  добавления в таблицу :

       # pfctl -t spammers -Tadd 218.70.0.0/16

  Это также откроет таблицу, если она не существует. Посмотреть значения
  в таблице:

       # pfctl -t spammers -Tshow

  Аргумент -v может использоваться совместно с -Tshow для отображнения
  каждой записи в таблице. Для удаления адреса из таблицы:

       # pfctl -t spammers -Tdelete 218.70.0.0/16

  Для получения дополнительной информации, смотрите pfctl(8).


Определение адресов:

  В дополнение к IP адресу, хосты могут обозначаться по имени. Когда имя
  хоста разрешается в IP адрес, то оно может быть помещено в таблицу.
  Также IP адреса могут быть введены в таблицу с использованием имени
  интерфейса или ключевого слова "self", при этом в таблицу будут
  добавляться все IP адреса, назначенные интерфейсу.


Соответствие адресов:

  Поиск адреса в таблице возвратит наиболее соответствующее значение.
  Это учитывается при создании таблиц типа:

       table  { 172.16.0.0/16, !172.16.1.0/24, 172.16.1.100 }
       block in on dc0 all
       pass  in on dc0 from  to any

  К любому пакету, входящему через dc0 будут применяться следующие
  правила:

    * 172.16.50.5 - самое точное соответствие - 172.16.0.0/16; пакет
      соответствует таблице и будет передаваться

    * 172.16.1.25 - самое точное соответствие - !172.16.1.0/24; пакет
      соответствует входу в таблицу, но тот вход инвертирован
      (использует "!" модификатор); пакет не соответствует таблице и
      будет блокирован

    * 172.16.1.100 - точное значение 172.16.1.100; пакет соответствует

      таблице и будет передан
    * 10.1.4.55 - не соответствует таблице и будет блокирован



Фильтрация пакетов
------------------

Введение:

  Фильтрация пакета - выборочное принятие или блокирование пакета,
  проходящего через сетевой интерфейс. pf(4) может использоваться для
  контроля пакетов на 3 уровне модели OSI (IPv4 и IPv6) и 4 уровне
  модели OSI (TCP, UDP, ICMP, и ICMPv6). Наиболее часто используется в
  качестве критериев оценки - протокол, адрес назначения, источник и
  порт адресата.

  Правила фильтра определяют критерии, которым пакет должен
  соответствовать. Правила просматриваются последовательно. Если пакет
  не соответствует правилу, содержащему ключевое слово quick, пакет
  будет оценен, как не соответствующий ни одному правилу, прежде, чем
  будетпросмотрен весь список. Приоритет имеет последнее правило списка,
  соответствующее пакету. Есть подход "разрешать все" в начале списка,
  тогда, если пакет не блокируется ни одним последующим правилом, он
  будет пропущен.


Синтаксис правил:

  Полный синтаксис правила:

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

  - action

  Действие, которое будет применяться к пакету - это pass или block.
  pass передаст пакет назад к ядру для дальнейшей обработки , в то время
  как block будет реагировать в соответствии с [16]block-policy. Реакция
  по умолчанию может быть отменена, определяя или block drop или block
  return.

  - direction

  Описывает направление движения пакета - in или out.

  - log

  Определяет, что пакет должен быть зарегистрирован через pflogd(8).
  Если правило определено как keep state, modulate state, или synproxy
  state, то будет зарегистрирован только первый пакет, создавший
  правило. Чтобы регистрировать все пакеты, используйте log-all.
 
  - quick

  Если пакет соответствует правилу quick, правило считают последним
  правилом соответствия, и предпринимается указанное действие.
 
  - interface

  Имя сетевого интерфейса, через который проходит пакет.
 
  - af

  Семейство адреса пакета, или inet для IPv4 или inet6 для IPv6. PF
  обычно способен определить этот параметр, анализируя источник и/или
  адрес назначения.
 
  - protocol

  Протокол пакета:
    * tcp
    * udp
    * icmp
    * icmp6
    * Имя протокола из [17]/etc/protocols
    * Номер протокола от 0 до 255
    * Используя [18]список

  - src_addr, dst_addr

  Источник/адрес назначения в заголовке IP. Адреса могут быть определены
  как:
    * Единственный адрес IPv4 или адрес IPv6.
    * Блок сети CIDR
    * Полностью определенное имя домена, которое будет определено через
      DNS после загрузки правил. Все определенные имена будут заменены
      IP адресами.
    * Имя сетевого интерфейса. Любые адреса, назначенные интерфейсу,
      будут вставлены в правило.
    * Имя сетевого интерфейса, сопровождаемого / сетевой маской
      (например /24). Каждый адрес на интерфейсе будет объединен с
      сетевой маской, чтобы формировать блок сети CIDR
    * Имя сетевого интерфейса в круглых скобках (). Это говорит PF
      модифицировать правило, если IP адрес(а) на названном интерфейсе
      изменяется. Это полезно на интерфейсе, получающего адрес через
      DHCP или модемного соединения, поскольку не надо каждый раз
      перезагружать правила.
    * Имя сетевого интерфейса, сопровождаемого ключевыми словами
      :network или :broadcast. В результате в правила будет загружен
      адрес сети CIDR (к примеру 192.168.0.0/24) или широковещательный
      адрес (к примеру 192.168.0.255)
    * Таблица.
    * Любое вышеупомянутое, но отрицаемое(инвертированное) с
      использованием ! ("не") модификатора.
    * Набор адресов, используя список
    * Ключевое слово any
    * Ключевое слово all, сокращенное от from any to any.

  - src_port, dst_port

  Порт источника/адресата. Порты могут быть определены как:
    * Номер между 1 и 65535
    * Имя протокола из [19]/etc/services
    * Набор портов, используя список
    * Диапазон:
         + ! = (не равный)
         + < (меньше чем)
         + > (больше чем)
         + <= (меньше чем или равный)
         + >= (больше чем или равный)
         + > <(диапазон)
         + <> (обратный диапазон)
      Последние два - двойные операторы (они берут два параметра) и не
      включают параметры в диапазон.

  - tcp_flags

  Определяет флаги, которые должны быть установлены в заголовке TCP при
  использовании proto tcp. Флаги определяются как flags check/mask.
  Например: flags S/SA - PF будет смотреть на S и A (SYN и ACK) флаги и
  соответствовать правилу, если установлен флаг SYN.
  state

  Определяет, сохраняется ли информация о состоянии на пакетах,
  соответствующих этому правилу.
    * keep state - работает с TCP, UDP, и ICMP
    * modulate state - работы только с TCP. PF генерирует Initial
      Sequence Numbers (ISNs) для пакетов, соответствующих этому
      правилу.
    * synproxy state - проксирует входящие TCP соединения, что помогает
      защищать сервера от TCP SYN флуда и спуфинга. Эта опция включает
      функциональные возможности keep state и modulate state.


Default Deny:

  Рекомендуемой практикой является "default deny".
  Для создания политики "default deny":

       block in  all
       block out all

  Это заблокирует все пакеты, протоколы, IP адреса отовсюду куда уго