Пакетный фильтр OpenBSD, часть 2

Опубликовано 28.12.2009

Перевод: Сгибнев Михаил

Оглавление




Опции запуска


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



set block-policy
    Устанавливает поведение по умолчанию для правил как всегда блокирующее:
  • drop — пакеты удаляются без уведомления

  • return — возвращается пакет TCP RST для блокированного TCP пакета и ICMP Unreachable для всего остального Обратите внимание, что индивидуальные правила фильтра могут отменить заданный по умолчанию ответ.


set debug
    Установить уровень отладки pf
  • none — отладочные сообщения не отображаются

  • urgent — отображаются серьезные ошибки. Является значением по умолчанию

  • misc — ошибки различной тяжести (например отображение статуса normalizer/scrubber пакета и ошибки создания правила state)

  • loud — отображать события, возникающие в ходе обычной работы (например результат работы пассивной системы определения удаленной ОС)


set fingerprints file
    Определить файл с сигнатурами операционных систем. Используется для пассивного определения удаленной ОС. По умолчанию /etc/pf.os.

set limit

  • frags — максимальный размер памяти в строках, используемой для пересборки пакета (scrub правило). По умолчанию 5000.

  • src-nodes — максимальный размер памяти в строках, используемой для хранения IP адресов источника. По умолчанию 10000.
  • states — максимальный размер памяти в строках, используемой для хранения таблицы состояний (правила фильтрации keep state). По умолчанию 10000.


set loginterface int
    Устанавливает интерфейс, но котором PF должен вести статистику по входящим/исходящим байтам и пропущенным/блокированным пакетам. Одновременно статистика собирается только для одного интерфейса. Обратите внимание на то, что счетчики в равилах работают независимо от того, установлен этот параметр или нет.

set optimization
    Оптимизирует работу PF руководствуясь следующими образцами:
  • normal — подходит почти для всех сетей. Является значением по умолчанию.

  • high-latency — сети с высоким временем задержки, например, спутниковые.

  • aggressive — позволяет уменьшить объемы занимаемой памяти за счет малого таймаута соединений в таблице состояний.

  • conservative — максимально консервативные настройки. Позволяет продлить время жизни записи в таблице состояний за счет некоторого увеличения объема занимаемой памяти и процессорного времени.


set state-policy
    Определяет манеру работы PF с таблицей состояний (см. Keeping State).
  • if-bound — правила привязаны к интерфейсу, на котором открыты. Если трафик соответствует записи, но пересекает интерфейс указанный в ней, то соответствия не произойдет. Тогда пакет должен соответствовать фильтрующему правилу или скинут/отброшен.

  • group-bound — также, как и с параметром if-bound, за исключением того, что принимаются интерфейсы одной группы — например все ppp интерфейсы.

  • floating — записи могут соответствовать пакету на любом интерфейсе. Пока пакет соответствует записи не имеет значения, через какой интерфейс он проходит и он будет пропущен. Является значением по умолчанию.


set timeout

  • interval — число секунд между пакетами, соответствующих правилу. Превышение приводит к удалению правила.

  • frag — время устаревания несобранного фрагмента пакета.


Пример:

set timeout interval 10
set timeout frag 30
set limit { frags 5000, states 2500 }
set optimization high-latency
set block-policy return
set loginterface dc0
set fingerprints /etc/pf.os.test
set state-policy if-bound

Scrub (Нормализация пакета)



  • Введение

  • Опции


Введение


«Scrubbing» —
это нормализация пакета таким образом, чтобы не осталось двусмысленности в определении адресата пакета. Директива scrub также пересобирает фрагментированные пакеты, таким образом осуществляя защиту некоторых операционных систем от определенного вида атак и отбрасывает пакеты с недопустимыми флагами. Самая простая форма:

scrub in all

Это позволит делать scrub всех пакетов на всех интерфейсах. Одной из причин не делать scrub — если вы прокидываете NFS через PF. Некоторые не-OpenBSD операционные системы посылают(и ожидают) странные пакеты — фрагментированные, но с установленным битом «do not fragment», которые будут отклоняться при использовании scrub. Это может быть решено с помощью опции no-df. Еще одной причиной могут быть некоторые игры, у которых могут возникнуть проблемы при работе через scrub.



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



Дополнительная информация может быть найдена в документе «Network Intrusion Detection: Evasion, Traffic Normalization, and End-to-End Protocol Semantics»



Опции


Scrub может принимать следующие опции:


no-df

    Убирает бит «don’t fragment» из заголовка IP пакета. Как уже говорилось, некоторые операционные системы генерируют фрагментированные пакеты с флагом «не фрагментировать», особенно это характерно для NFS. Такие пакеты будут отброшены, если не использовать no-df. Поскольку некоторые ОС генерируют «don’t fragment» пакеты с нулевым идентификатором IP в заголовке, использование no-df лучше сочетать с опцией random-id.

random-id

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

min-ttl num

    Устанавливает минимальное значение Time To Live (TTL) в заголовке пакета.

max-mss num

    Устанавливает Maximum Segment Size (MSS) в заголовке TCP пакета.

fragment reassemble

    Приходящие фрагменты накапливаются и собираются в законченный пакет, который затем передается на механизм фильтрации. Преимущество — возможность фильтрующему правилу игнорировать фрагменты. Недостаток — увеличение расхода памяти. Это опция по умолчанию, если никакая другая опция работы с фрагментами не установлена. Также это единственная опция, с которой работает NAT.

fragment crop

    Все дублированные фрагменты будут отброшены и любые превышения — обрезаны. В отличие от fragment reassemble, фрагменты не буферизуются и передаются на механизм фильтрации сразу.

fragment drop-ovl

    Работает подобно fragment crop, за исключением того, что все дубликаты отбрасываются.

reassemble tcp

    Постоянно нормализует TCP пакеты. При использовании scrub пересобирает пакет, может быть не определено направление (in/out). Может быть выполнена следующая нормализация:
  • Ни одной из сторон не позволяется уменьшить IP TTL. Это сделано для того, чтобы защититься от посылок пакетов, запрашивающих соединение, но исчезающих до достижения адресата. TTL всех пакетов устанавливается в максимум.

  • Модуляция временных меток RFC1323 в заголовке TCP пакета со случайным числом. Это препятствует определению uptime хоста или определению количества хостов за маршрутизатором, использующем NAT.


Пример:

scrub in on fxp0 all fragment reassemble min-ttl 15 max-mss 1400
scrub in on fxp0 all no-df
scrub on fxp0 all reassemble tcp

Именованные (под)наборы правил и якоря



  • Введение

  • Именованные наборы правил

  • Опции якоря

  • Управление именованными наборами


Введение



В дополнению к главному набору правил, PF может работать с дополнительными наборами. С тех пор, как поднаборы могут динамически изменяться используя pfctl(8), они стали удобным инструментом изменения основного набора правил. Если таблица используется для динамического хранения адресов, поднаборы используются для динамического хранения правил фильтрации и правил nat, rdr, и binat.



Поднабор может быть добавлен в главный набор с помощью якоря. Есть четыре типа якорных правил:

  • anchor name — оценивает все правила фильтра по имени якоря

  • binat-anchor name — оценивает правила binat фильтра по имени якоря

  • nat-anchor name — оценивает правила nat фильтра по имени якоря

  • rdr-anchor name — оценивает правила rdr фильтра по имени якоря


Только главный набор правил может содержать якорные правила.



Именованные наборы правил



Именованный набор — это группа правил фильтрации группа фильтра и/или правил трансляции, которым было назначено имя. Точка привязки может содержать больше чем один такой набор. Когда PF обнаруживает якорь в главном наборе правил, он производит проверку всех поднаборов правил, привязанных к нему, в алфавитном порядке, согласно их именам. Проверка правил в главном наборе начинается в том случае, когда пакет не соответствует фильтру, если встречается опция quick или правило трансляции пакет прекращает прохождение правил и основного и поднабора.



Например:

ext_if = "fxp0"

block on $ext_if all
pass out on $ext_if all keep state
anchor goodguys

Этот набор правил устанавливает по умолчанию запретительную политику на интерфейсе fxp0 для всего входящего и исходящего трафика. Stateful трафик пропускается и создается якорное правило с именем goodguys. Якоря могут быть связаны с правилами двумя методами: * Используя загрузку правил * Используя pfctl(8) Загрузка правил указывает pfctl загрузить правила из текстового файла. Например:

load anchor goodguys:ssh from "/etc/anchor-goodguys-ssh"

Когда будет загружен главный набор, правила, перечисленные в файле/etc/anchor-goodguys-ssh будут загружены в именованный набор ssh, приложенный к якорю goodguys.



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

# echo "pass in proto tcp from 192.0.2.3 to any port 22" | pfctl -a goodguys:ssh -f -

Это добавит правило pass правила ssh к якорю goodguys. PF проверит эти правила (а также любые другие правила фильтрации, которые будут добавлены) когда дойдет до якоря goodguys в главном наборе правил.



Правила также могут быть сохранены и загружены из текстового файла:

# cat >> /etc/anchor-goodguys-www
pass in proto tcp from 192.0.2.3 to any port 80
pass in proto tcp from 192.0.2.4 to any port { 80 443 }

# pfctl -a goodguys:www -f /etc/anchor-goodguys-www

Эта операция загрузит правила из файла /etc/anchor-goodguys-www в именованый набор правил www якоря
goodguys.



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



Каждый именованный набор существует обособленно от остальных. Операции, проводимые над ним, такие как сброс правил, не имеют эффекта над остальными. Кроме того, удаление указателя на якорь не приводит к удалению ни самого якоря ни именованных наборов правил, к нему привязанных. Именованный набор существует до тех пор, пока все его правила не будут сброшены, используя pfctl(8). Якорь уничтожается как только не остается ни одного привязанного к нему набора правил.


Опции якоря



Дополнительно в якорном правиле может быть определен интерфейс, протокол, адрес источника или назначения, тэг и т.д. Когда такой дополнительный параметр встречается, то пакет попадает на проверку только в случае соответствия указанному условию. Например:

ext_if = "fxp0"

block on $ext_if all
pass out on $ext_if all keep state
anchor ssh in on $ext_if proto tcp from any to any port 22

Правила в якоре ssh будут оцениваться только в случае, если пришел TCP пакет на 22 порт. Правила к якорю могут добавляться так:

# echo "pass in from 192.0.2.10 to any" | pfctl -a ssh:allowed -f -

В этом случае, когда не определен ни порт, ни протокол, ни интерфейс, хосту 192.0.2.10 будет разрешена работа только по протоколу ssh.



Управление именованными наборами



Управление осуществляется с помощью pfctl. Вы можете удалять и добавлять правила из набора не перезагружая при этом главный набор.



Для примера, выведем список всех правил набора, добавленного к якорю ssh:

# pfctl -a ssh:allowed -s rules

Сброс всех правил из этого набора:

# pfctl -a ssh:allowed -F rules

Если имя набора пропущено, то действие применяется ко всем наборам якоря.


Для получения полного списка команд, пожалуйста см. pfctl(8).

Организация очередей и приоритетов



  • Очереди

  • Планировщики

    • Очереди, базирующиеся на классах

    • Приоритетные очереди

    • Случайное раннее обнаружение

    • Явное уведомление о перегрузке



  • Конфигурирование очереди

  • Назначение трафика в очередь

  • Пример #1: Маленькая домашняя сеть

  • Пример #2: Сеть компании


Очереди



Как известно, смысл очереди заключается в том, чтобы сохранить данные, которые еще не прошли обработку. При работе в сети, данные получаемые хостом поступают в очередь и ждут, когда они будут обработаны операционной системой, при этом она решает, какие именно пакеты и в каком порядке обрабатывать. Изменение этого порядка может оказать влияние на производительность сети. Для примера, представьте себе пользователя, работающего одновременно с приложениями по протоколам ssh и ftp. В идеальном случае, пакеты ssh должны обрабатываться в первую очередь, так как этот протокол очень чувствителен к задержкам. При нажатии клавиши в ssh-клиенте ожидается немедленный ответ, но идущая передача по ftp вызывает задержку в несколько секунд. Что может произойти в случае, когда роутер обрабатывает большое количество ftp пакетов? Пакеты ssh сохраняются в очереди, а то и просто отбрасываются в случае малого буфера и в результате ssh сессия может вообще прерваться. Модифицирование стратегии организации очередей может позволить распределить пропускную способность между различными приложениями, пользователями и хостами.



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



Планировщики



Планировщиком называется то, что организовывает очередь и определяет порядок обработки пакетов. По умолчанию в OpenBSD в качестве планировщика используется First In First Out (FIFO). Принцип его очень просто — первый вошел — первый вышел. Новоприбывший пакет добавляется в конец очереди. При превышении максимального размера очереди пакет отбрасывается. Это явление известно как tail-drop.



OpenBSD поддерживает два планировщика:

  • Очереди, базирующиеся на классах (Class Based Queueing)

  • Приоритетные очереди (Priority Queueing)


Очереди, базирующиеся на классах



В очередях базирующиеся на классах (CBQ) алгоритм организации очереди построен на разделении полосы пропускания между различными очередями или классами. Трафик присоединяется к очереди на основании адреса источника или отправителя, порта, протокола и т.д. и т.п. Очередь может быть сконфигурирована на заимствование произвольной полосы пропускания от родительской очереди, если та занимает свой канал не полностью. Очереди также могут работать с системой приоритетов, например, пропуская ssh трафик в первую очередь, по сравнению с трафиком ftp.



В CBQ очереди размещаются иерархическим способом. В самом верху — родительская очередь, определяющая общую пропускную способность. Дочерним очередям назначается некоторая часть от полосы пропускания родительской очереди. Например, очереди могут быть определены
следующим способом

Root Queue (2Mbps)

Queue A (1Mbps)
Queue B (500Kbps)
Queue C (500Kbps)

В этом случае общая пропускная способность составляет 2 МБ/с и эта полоса пропускания делится между тремя дочерними очередями.



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

Root Queue (2Mbps)

UserA (1Mbps)

ssh (50Kbps)
bulk (950Kbps)

UserB (1Mbps)

audio (250Kbps)
bulk (750Kbps)

http (100Kbps)
other (650Kbps)

Обратите внимание, что на каждом уровне сумма полос пропускания не может быть больше родительской.



Очередь может быть настроена таким образом, что будет заимствовать полосу пропускания у родителя в случае неиспользования ее другими очередями. Рассмотрим такую организацию очереди:

Root Queue (2Mbps)

UserA (1Mbps)

ssh (100Kbps)
ftp (900Kbps, borrow)

UserB (1Mbps)

Если трафик в ftp очереди превышает 900Kbps, и трафик в очереди UserA — меньше чем 1Mbps (потому что ssh очередь использует меньше чем 100Kbps), ftp очередь заимствует дополнительную полосу пропускания от UserA. Таким образом ftp очередь способна использовать больше чем ей назначенные 900Kbps, но в случае увеличения очереди ssh заимствованая полоса освобождается.



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

Root Queue (2Mbps)

UserA (1Mbps, priority 1)

ssh (100Kbps, priority 5)
ftp (900Kbps, priority 3)

UserB (1Mbps, priority 1)

CBQ будет обрабатывать очереди UserA и UserB циклическим способом, так как их приоритеты равны. В ходе обработки очереди UserA также обрабатываются ее дочерние очереди, где ssh имеет более высокий приоритет и будет обрабатываться в первую очередь в случае перегрузки сети. Обратите внимание, что очереди ssh и ftp е имеют приоритета по сравнению с очередями UserA и UserB так как они находятся на более низком уровне.



Для получения более детальной информации по CBQ обратитесь к References on CBQ.



Приоритетные очереди



Приоритетные очереди (PRIQ) создаются на сетевом интерфейсе, причем структура очередей является плоской — нельзя создавать дочерние очереди. Сперва определяется корневая очередь с указанием общей пропускной способности, а за ней все дочерние очереди. Рассмотрим такой пример:

Root Queue (2Mbps)

Queue A (priority 1)
Queue B (priority 2)
Queue C (priority 3)

Корневая очередь определяется с пропускной способностью 2Mbps, следом идут дочерние.



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



Случайное раннее обнаружение



Случайное раннее обнаружение (RED) — это алгоритм определения перегрузки канала. Его целью является предотвращение переполнения очереди. Делается это путем непрерывного сравнения текущей длины очереди к минимальному и максимальному порогам. Если минимальный порог не достигнут — все пакеты пропускаются. Если достигнут максимальные порог — все пакеты отбрасываются. В промежутке пакеты отбрасываются с определенной вероятностью, зависящей от размера очереди. Чем ближе к максимальному порогу — тем выше вероятность. Пакеты для отбрасывания выбираются случайным образом из разных сессий. Чем большая полоса пропускания занимается сессией, тем более выше вероятность сброса из нее пакета.



RED весьма полезен, так как позволяет избежать ситуации, называемой «глобальной синхронизацией», она проявляется в том, что связь полностью прекращается из-за одновременно отбрасываемых пакетов с разных сессий. Например, если перегрузка происходит на маршрутизаторе, обслуживающем 10 одновременных сессий ftp и будут отброшены пакеты от большинства или всех сессий, общая пропускная способность резко понизится. RED позволяет избежать этого, выбирая сессии из которых терять пакеты случайным образом. Поскольку сессии занимающие больше полосы пропускания имеют больший шанс на потерю пакета, то возможность возникновения перегрузки исчезнет и больших потерь трафика не произойдет. Кроме того, RED позволяет обработать взрывной всплеск трафика, так как начинает отбрасывать пакеты до переполнения очереди.



RED должен использоваться только тогда, когда транспортный протокол способен реагировать на индикаторы перегрузки сети. В большинстве случаев это означает, что RED должен использоваться только к очередям TCP, а не к очередям UDP или ICMP.



Для получения дополнительной информации обратитесь к References on RED.



Явное уведомление о перегрузке



Явное уведомление о перегрузке (ECN) работает совместно с RED и применяется для уведомления двух связанных хостов о перегрузке сети. Делается это разрешением RED установить флаг в заголовке пакета, вместо его отброса. Если удаленный хост поддерживает ECN и читает этот флаг, то он начинает снижать исходящий трафик.



Для получения более подробной информации обратитесь к RFC 3168.



Конфигурирование очереди



Начиная с OpenBSD 3.0 Alternate Queueing (ALTQ) стал частью основной системы, а с версии OpenBSD 3.3 ALTQ был интегрирован в PF. Реализация ALTQ в OpenBSD поддерживает планировщики Class Based Queueing (CBQ) and Priority Queueing (PRIQ) и Random Early Detection (RED) вместе с Explicit Congestion Notification (ECN)..



Поскольку ALTQ интегрирован в PF, то PF должен быть включен для организации работы очередей. Руководство, как это сделать, можно найти в разделе документации «Getting Started».


Очереди конфигурируются в файле pf.conf. Есть два типа директив, которые используются для конфигурации очередей.


  • altq on — определяет интерфейс, на котором будет организована очередь, планировщик и создает корневую очередь.

  • queue — определяет свойства дочерних очередей


Синтаксис директивы altq следующий:

altq on interface scheduler bandwidth bw qlimit qlim \
tbrsize size queue { queue_list }


  • interface — сетевой интерфейс, на котором активируется очередь.

  • scheduler — какой планировщик будет использован. Доступные значения cbq и priq. На интерфейсе в один момент времени можно установить только один планировщик.

  • bw — общая пропускная способность, доступная планировщику. Может содержать аббревиатуры b, Kb, Mb, Gb для обозначения bits, kilobits, megabits, и gigabits в секунду, конкретное значение или процент от общей пропускной способности.

  • qlim — максимальное число пакетов в очереди. Необязательный параметр. По умолчанию — 50

  • size — размер token bucket regulator в байтах. Если не определен, то устанавливается на основе ширины полосы пропускания.

  • queue_list — список дочерних очередей, открываемых из под родительской очереди.


Например:

altq on fxp0 cbq bandwidth 2Mb queue { std, ssh, ftp }

Эта команда запускает CBQ на интерфейсе fxp0, пропускная способность канала 2Mb и создаются три дочерние очереди std, ssh, ftp.



Синтаксис кдирективы queue следующий:

queue name [on interface] bandwidth bw [priority pri] [qlimit qlim] \
scheduler ( sched_options ) { queue_list }


  • name — имя очереди. Эта запись должна быть идентична определенной в директиве altq опцией queue_list. Для cbq это также может быть запись имени очереди в предыдущей директиве queue параметре queue_list. Имя не должно быть длиннее 15 символов.

  • interface — сетевой интерфейс, на котором запущена очередь. Это значение опциональное и если не определено, то очередь будет работать применительно ко всем интерфейсам.

  • bw — общая пропускная способность, доступная планировщику. Может содержать аббревиатуры b, Kb, Mb, Gb для обозначения bits, kilobits, megabits, и gigabits в секунду, конкретное значение или процент от общей пропускной способности. Указывается только при использовании планировщика cbq.

  • pri — приоритет очереди. Для cbq приоритет изменяется от 0 до 7, для priq диапазон от 0 до 15. Приоритет 0 считается самым низким. Если этот параметр не определен, ему назначается 1.

  • qlim — максимальное число пакетов в очереди. Необязательный параметр. По умолчанию — 50

  • scheduler — используемый планировщик — cbq или priq. Должен быть таким же, как и родительская очередь.

  • sched_options — дополнительные опции для управления планировщиком:

    • default — определить очередью по умолчанию, куда будут включаться все пакеты не подходящие под остальные очереди. Может быть только одна.

    • red — включить Random Early Detection (RED) для этой очереди.

    • rio — включить RED с IN/OUT. В этом режиме RED поддерживает очереди различной длины и различные пороговые значения, по одному на каждый уровень IP Quality of Service.

    • ecn — включить Explicit Congestion Notification (ECN) для этой очереди. Ecn работает совместно с red.

    • borrow — эта очередь может заимствовать пропускную способность у других очереде. Может быть определено только при использовании cbq.


  • queue_list — список дочерних очередей. Может быть определено только при использовании cbq.


Продолжение примера выше:

queue std bandwidth 50% cbq(default)
queue ssh { ssh_login, ssh_bulk }
queue ssh_login priority 4 cbq(ecn)
queue ssh_bulk cbq(ecn)
queue ftp bandwidth 500Kb priority 3 cbq(borrow red)

Здесь определяются дочерние очереди. Очереди std назначается 50% пропускной способности от материнской очереди и она назначается дефолтной. Очередь ssh определяет две дочерних очереди, ssh_login и ssh_bulk. Ssh_login дают более высокий приоритет чем ssh_bulk, и обе работают с ECN. Ftp назначена полоса пропускания в 500Kbps и дан приоритет 3. Эта очередь может арендовать свободную пропускную способность других очередей и используется red.



Назначение трафика в очередь


Для направления трафика в очередь используется ключевое слово queue в правилах PF. Для примера рассмотрим следующую строку:

pass out on fxp0 from any to any port 22

Пакеты из этого правила могут быть направлены в очередь таким способом:

pass out on fxp0 from any to any port 22 queue ssh

Когда используется ключевое слово queue совместно с директивой block, все пакеты TCP RST или ICMP Unreachable ставятся в указанную очередь.



Обратите внимание, что queue может приключиться для другого интерфейся, чем было определено директивой
altq:

altq on fxp0 cbq bandwidth 2Mb queue { std, ftp }
queue std cbq(default)
queue ftp bandwidth 1.5Mb

pass in on dc0 from any to any port 21 queue ftp

Очередь определяется на fxp0, но указание на нее встречается на dc0. Если пакет, соответствующие правилу выходит с интерфейса fxp0, то он будет поставлен в очередь ftp. Этот тип очередей может быть очень полезен на маршрутизаторах.



Обычно с ключевым словом queue используется только одно имя очереди, но если определено и второе имя, то очередь будет использоваться для пакетов с Type of Service(ToS) низкой задержки и для пакетов TCP ACK без полезного груза данных. Хороший пример может быть найден при использовании ssh: во время открытия сессии ToS устанавливается в low-delay пока не откроется сессия SCP или SFTP. PF может использовать информацию о находящихся в очереди пакетах для того. чтобы отличить пакеты на ввод логина от остальных пакетов. Возможно будет полезным разнести по приоритетам пакеты авторизации от пакетов данных:

pass out on fxp0 from any to any port 22 queue(ssh_bulk, ssh_login)

Это правило позволяет связать пакеты авторизации ssh с очередью ssh_login, а пакеты SCP и SFTP с очередью ssh_bulk, при этом ssh_login имеет приоритет выше и пакеты авторизации снуют во все стороны значительно швыдче.



Повышение приоритета пакетов TCP ACK имеет смысл на асинхронных соединениях, таких как ADSL, где скорость входящего и исходящего потока не равны между собой. На ADSL линии при полностью занятом исходящем канале будет снижаться и полезное использование входящего канала, так как пакеты TCP ACK будут теряться и задерживаться. Тестирования показали, что для достижения наибольшей эффективности, полоса пропускания должна быть немного меньше, чем способно подключение. Например, если ADSL линия дает максимальную скорость в 640Kbps, установите значение пропускной способности для корневой линии в 600Kb. Оптимальное значение находится путем проб и ошибок.


Когда ключевое слово queue используется с правилами keep state:

pass in on fxp0 proto tcp from any to any port 22 flags S/SA keep state queue ssh

PF будет делать запись очереди в таблице состояний таким образом, что пакеты с fxp0 соответствующие образовавшемуся соединению будут оказываться в очереди ssh.



Обратите внимание, что ключевое слово queue применяется к правилам, обслуживающим входящий трафик.


Пример #1: Маленькая домашняя сеть

[ Alice ] [ Charlie ]
| | ADSL
---+-----+-------+------ dc0 [ OpenBSD ] fxp0 -------- ( Internet )
|
[ Bob ]
В этом примере OpenBSD используется как шлюз в
Интернет для маленькой домашней сети с тремя рабочими станциями. На
шлюзе работает NAT и фильтрация пакетов. Выход в Интернет
осуществляется по ADSL с входящей скоростью 2Mbps и исходящей
640Kbps.



Для очередей действуют следующие правила:


  • Выделяем 80Kbps для игрулек Боба, чтобы не стонал, когда Алиса и Чарли качают фильмы и музыку. Когда есть свободная полоса — пусть берет.

  • SSH трафик и трафик интернет — пейджеров имеет высший приоритет.

  • DNS запросы-ответы имеют приоритет чуть ниже.

  • Исходящие TCP ACK имеют высший приоритет по сравнению со всем остальным исходящим трафиком.


Ниже представлены правила, реализующие эту политику. Обратите внимание, что в pf.conf не представлены правила nat, rdr, options, и т.д. непосредственно не имеющие отношения.

# enable queueing on the external interface to control traffic going to
# the Internet. use the priq scheduler to control only priorities. set
# the bandwidth to 610Kbps to get the best performance out of the TCP
# ACK queue.

altq on fxp0 priq bandwidth 610Kb queue { std_out, ssh_im_out, dns_out, \
tcp_ack_out }

# define the parameters for the child queues.
# std_out - the standard queue. any filter rule below that does not
# explicitly specify a queue will have its traffic added
# to this queue.
# ssh_im_out - interactive SSH and various instant message traffic.
# dns_out - DNS queries.
# tcp_ack_out - TCP ACK packets with no data payload.

queue std_out priq(default)
queue ssh_im_out priority 4 priq(red)
queue dns_out priority 5
queue tcp_ack_out priority 6

# enable queueing on the internal interface to control traffic coming in
# from the Internet. use the cbq scheduler to control bandwidth. max
# bandwidth is 2Mbps.

altq on dc0 cbq bandwidth 2Mb queue { std_in, ssh_im_in, dns_in, bob_in }

# define the parameters for the child queues.
# std_in - the standard queue. any filter rule below that does not
# explicitly specify a queue will have its traffic added
# to this queue.
# ssh_im_in - interactive SSH and various instant message traffic.
# dns_in - DNS replies.
# bob_in - bandwidth reserved for Bob's workstation. allow him to
# borrow.

queue std_in cbq(default)
queue ssh_im_in priority 4
queue dns_in priority 5
queue bob_in bandwidth 80Kb cbq(borrow)

# ... in the filtering section of pf.conf ...

alice = "192.168.0.2"
bob = "192.168.0.3"
charlie = "192.168.0.4"
local_net = "192.168.0.0/24"
ssh_ports = "{ 22 2022 }"
im_ports = "{ 1863 5190 5222 }"

# filter rules for fxp0 inbound
block in on fxp0 all

# filter rules for fxp0 outbound
block out on fxp0 all
pass out on fxp0 inet proto tcp from (fxp0) to any flags S/SA \
keep state queue(std_out, tcp_ack_out)
pass out on fxp0 inet proto { udp icmp } from (fxp0) to any keep state
pass out on fxp0 inet proto { tcp udp } from (fxp0) to any port domain \
keep state queue dns_out
pass out on fxp0 inet proto tcp from (fxp0) to any port $ssh_ports \
flags S/SA keep state queue(std_out, ssh_im_out)
pass out on fxp0 inet proto tcp from (fxp0) to any port $im_ports \
flags S/SA keep state queue(ssh_im_out, tcp_ack_out)

# filter rules for dc0 inbound
block in on dc0 all
pass in on dc0 from $local_net

# filter rules for dc0 outbound
block out on dc0 all
pass out on dc0 from any to $local_net
pass out on dc0 proto { tcp udp } from any port domain to $local_net \
queue dns_in
pass out on dc0 proto tcp from any port $ssh_ports to $local_net \
queue(std_in, ssh_im_in)
pass out on dc0 proto tcp from any port $im_ports to $local_net \
queue ssh_im_in
pass out on dc0 from any to $bob queue bob_in

Пример #2: Сеть компании

( IT Dept ) [ Boss's PC ]
| | T1
--+----+-----+---------- dc0 [ OpenBSD ] fxp0 -------- ( Internet )
| fxp1
[ COMP1 ] [ WWW ] /
| /
--+----------'

В этом примере OpenBSD выступает в роли системы сетевой защиты для сети компании. В компании работает WWW сервер, установленный в DMZ. Клиенты обновляют свои сайты через FTP. У IT одела имеется собственная подсеть, соединенная с главной, босс использует свой компьютер для почты и серфинга по сети. Соединение с Интернетом осуществляется на скорости T1 (1.5Mbps) в обе стороны. Все прочие сетевые сегменты используют Fast Ethernet (100Mbps).



Сетевой администратор выбрал следующую политику:


  • Трафик между WWW сервером и Интернетом ограничивается 500Kbps на одно соединение.

  • Между WWW сервером и внутренней сетью ограничения по скорости нет.

  • Трафик HTTP между WWW сервером и Интернет имеет высший приоритет по сравнению со всем остальным трафиком от WWW в Internet (таким, как доступ по FTP).

  • 500Kbps резервируется для IT для того, чтобы качать последние версии программного обеспечения. Если есть лишнее — забираем.

  • Трафик между начальником и Интернетом имеет высший приоритет по сравнению со сравнению со всем.


Ниже представлены правила, реализующие эту политику. Обратите внимание, что в pf.conf не представлены правила nat, rdr, options, и т.д. непосредственно не имеющие отношения.

# enable queueing on the external interface to queue packets going out
# to the Internet. use the cbq scheduler so that the bandwidth use of
# each queue can be controlled. the max outgoing bandwidth is 1.5Mbps.

altq on fxp0 cbq bandwidth 1.5Mb queue { std_ext, www_ext, boss_ext }

# define the parameters for the child queues.
# std_ext - the standard queue. also the default queue for
# outgoing traffic on fxp0.
# www_ext - container queue for WWW server queues. limit to
# 500Kbps.
# www_ext_http - http traffic from the WWW server
# www_ext_misc - all non-http traffic from the WWW server
# boss_ext - traffic coming from the boss's computer

queue std_ext cbq(default)
queue www_ext bandwidth 500Kb { www_ext_http, www_ext_misc }
queue www_ext_http priority 3 cbq(red)
queue www_ext_misc priority 1
queue boss_ext priority 3

# enable queueing on the internal interface to control traffic coming
# from the Internet or the DMZ. use the cbq scheduler to control the
# bandwidth of each queue. bandwidth on this interface is set to the
# maximum. traffic coming from the DMZ will be able to use all of this
# bandwidth while traffic coming from the Internet will be limited to
# 1.0Mbps (because 0.5Mbps (500Kbps) is being allocated to fxp1).

altq on dc0 cbq bandwidth 100% queue { net_int, www_int }

# define the parameters for the child queues.
# net_int - container queue for traffic from the Internet. bandwidth
# is 1.0Mbps.
# std_int - the standard queue. also the default queue for outgoing
# traffic on dc0.
# it_int - traffic to the IT Dept network.
# boss_int - traffic to the boss's PC.
# www_int - traffic from the WWW server in the DMZ.

queue net_int bandwidth 1.0Mb { std_int, it_int, boss_int }
queue std_int cbq(default)
queue it_int bandwidth 500Kb cbq(borrow)
queue boss_int priority 3
queue www_int cbq(red)

# enable queueing on the DMZ interface to control traffic destined for
# the WWW server. cbq will be used on this interface since detailed
# control of bandwidth is necessary. bandwidth on this interface is set
# to the maximum. traffic from the internal network will be able to use
# all of this bandwidth while traffic from the Internet will be limited
# to 500Kbps.

altq on fxp1 cbq bandwidth 100% queue { internal_dmz, net_dmz }

# define the parameters for the child queues.
# internal_dmz - traffic from the internal network.
# net_dmz - container queue for traffic from the Internet.
# net_dmz_http - http traffic.
# net_dmz_misc - all non-http traffic. this is also the default queue.

queue internal_dmz # no special settings needed
queue net_dmz bandwidth 500Kb { net_dmz_http, net_dmz_misc }
queue net_dmz_http priority 3 cbq(red)
queue net_dmz_misc priority 1 cbq(default)

# ... in the filtering section of pf.conf ...

main_net = "192.168.0.0/24"
it_net = "192.168.1.0/24"
int_nets = "{ 192.168.0.0/24, 192.168.1.0/24 }"
dmz_net = "10.0.0.0/24"

boss = "192.168.0.200"
wwwserv = "10.0.0.100"

# default deny
block on { fxp0, fxp1, dc0 } all

# filter rules for fxp0 inbound
pass in on fxp0 proto tcp from any to $wwwserv port { 21, \
> 49151 } flags S/SA keep state queue www_ext_misc
pass in on fxp0 proto tcp from any to $wwwserv port 80 \
flags S/SA keep state queue www_ext_http

# filter rules for fxp0 outbound
pass out on fxp0 from $int_nets to any keep state
pass out on fxp0 from $boss to any keep state queue boss_ext

# filter rules for dc0 inbound
pass in on dc0 from $int_nets to any keep state
pass in on dc0 from $it_net to any queue it_int
pass in on dc0 from $boss to any queue boss_int
pass in on dc0 proto tcp from $int_nets to $wwwserv port { 21, 80, \
> 49151 } flags S/SA keep state queue www_int

# filter rules for dc0 outbound
pass out on dc0 from dc0 to $int_nets

# filter rules for fxp1 inbound
pass in on fxp1 proto { tcp, udp } from $wwwserv to any port 53 \
keep state

# filter rules for fxp1 outbound
pass out on fxp1 proto tcp from any to $wwwserv port { 21, \
> 49151 } flags S/SA keep state queue net_dmz_misc
pass out on fxp1 proto tcp from any to $wwwserv port 80 \
flags S/SA keep state queue net_dmz_http
pass out on fxp1 proto tcp from $int_nets to $wwwserv port { 80, \
21, > 49151 } flags S/SA keep state queue internal_dmz

Адресные пулы и балансировка нагрузки



  • Введение

  • Адресные пулы NAT

  • Балансировка нагрузки входящих подключений

  • Балансировка нагрузки исходящего трафика

    • Пример набора правил




Введение


Адресным пулом называется адресное пространство больше двух адресов используемое группой пользователей. Адресный пул может быть указан в правилах перенаправления, трансляции и указан как адрес назначения в опциях фильтрации route-to, reply-to и dup-to.



Есть четыре метода использования пулов адресов:

  • bitmask — назначает адрес из пула согласно исходному сетевому адресу (адрес источника для правил nat, адрес назначения для правил rdr). Пример: если пул адресов включает 192.0.2.1/24 и модифицируемый адрес 10.0.0.50, то результирующим адресом будет 192.0.2.50. Если пул адресов включает 192.0.2.1/25 и модифицируемый адрес 10.0.0.130, результатом будет 192.0.2.2.

  • random — случайный выбор адресов из пула.

  • source-hash — использование хэша адреса источника для распределения адресов из пула. Этот метод гарантирует соответствие адреса источника и адреса, взятого из пула. Ключ для алгоритма хеширования может быть определен дополнительно после ключевого слова source-hash в шестнадцетиричном формате или как строка. По умолчанию, pfctl(8) генерирует случайный ключ при каждой загрузке набора правил.

  • round-robin — использование адресов пула по кругу. Это метод по умолчанию и единственный метод, когда пул адресов определен из таблицы.

За исключением метода round-robin, пул адресов должен быть определен как блок адресов CIDR (Classless Inter-Domain Routing). В методе round-robin используется назначение адресов из таблицы.



Опция sticky-address может использоваться с пулами random и round-robin для гарантии назаначения всегда одного и того же адреса источника в адрес пула.



Адресные пулы NAT



Здесь пул адресов используется для трансляции адресов в правилах nat. Соединение, которое имеет адрес источника транслируется в адрес пула, при этом базируясь на определенном методе. Это может оказаться очень полезным в случае. когда PF транслирует адреса для очень большой сети. Так как число одновременных NAT соединений на один внешний адрес ограниченно, выделение для этих целей пула адресов позволит значительно увеличить число пользователей.


В этом примере пул из двух адресов используется для трансляции исходящих пакетов. Для каждого исходящего соединения PF производит ротацию адресов методом
round-robin:

nat on $ext_if inet from any to any -> { 192.0.2.5, 192.0.2.10 }

Единственным недостатком этого метода будет то, что не всегда будет соблюдаться соответствие между исходным адресом и адресом трансляции. Это может вызвать проблему при заходе на web — узлы, проверяющих валидность пользователя на основании IP адреса. Решением этой проблемы может стать использование метода source-hash для привязки внутреннего адреса к адресу трансляции. В этом случае адресный пул должен быть определен как сетевой блок CIDR:

nat on $ext_if inet from any to any -> 192.0.2.4/31 source-hash

В этом правиле nat используется пул адресов 192.0.2.4/31 (192.0.2.4 — 192.0.2.5) как адреса трансляции для исходящих пакетов. Каждый внутренний адрес будет всегда транслироваться в свой внешний адрес, так как указано ключевое слово
source-hash.



Балансировка нагрузки входящих подключений



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

web_servers = "{ 10.0.0.10, 10.0.0.11, 10.0.0.13 }"

rdr on $ext_if proto tcp from any to any port 80 -> $web_servers \
round-robin sticky-address

Все соединения циклически будут перенаправляться на серверы фермы используя метод round-robin. Это «sticky connection» будет существовать до тех пор, пока существуют постоянные соединения к этому адресу. Следующий пользователь будет подключен иже с следующему адресу.



Балансировка нагрузки исходящего трафика



Пулы адресов могут использоваться для балансировки нагрузки между двумя и более внешними каналами с использованием опции route-to в случае невозможности организовать динамическую маршрутизацию (например, с использованием протокола BGP4). Совместное использование route-to и пула адресов round-robin исходящие соединения могут быть распределены между разными провайдерами.



В качестве дополнительной информации необходимо указать адреса маршрутизаторов для каждого Интернет-соединения. Это необходимо для опции route-to, дабы управлять исходящими пакетами.



Этот пример покажет нам балансировку нагрузки между двумя каналами:

lan_net = "192.168.0.0/24"
int_if = "dc0"
ext_if1 = "fxp0"
ext_if2 = "fxp1"
ext_gw1 = "68.146.224.1"
ext_gw2 = "142.59.76.1"

pass in on $int_if route-to \
{ ($ext_if1 $ext_gw1), ($ext_if2 $ext_gw2) } round-robin from $lan_net to any keep state

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

Для гарантии того, что пакеты с $ext_if1 всегда направляются к $ext_gw1 (и соответственно для $ext_if2 к $ext_gw2), в правилах можно указать следующее:

pass out on $ext_if1 route-to ($ext_if2 $ext_gw2) from $ext_if2 to any
pass out on $ext_if2 route-to ($ext_if1 $ext_gw1) from $ext_if1 to any

В заключение хочу сказать, что NAT можно использовать на каждом из внешних интерфейсов:

nat on $ext_if1 from $lan_net to any -> ($ext_if1)
nat on $ext_if2 from $lan_net to any -> ($ext_if2)

Полный пример балансировки исходящего трафика будет выглядеть так:

lan_net = "192.168.0.0/24"
int_if = "dc0"
ext_if1 = "fxp0"
ext_if2 = "fxp1"
ext_gw1 = "68.146.224.1"
ext_gw2 = "142.59.76.1"

# nat outgoing connections on each internet interface
nat on $ext_if1 from $lan_net to any -> ($ext_if1)
nat on $ext_if2 from $lan_net to any -> ($ext_if2)

# default deny
block in from any to any
block out from any to any

# pass all outgoing packets on internal interface
pass out on $int_if from any to $lan_net
# pass in quick any packets destined for the gateway itself
pass in quick on $int_if from $lan_net to $int_if
# load balance outgoing tcp traffic from internal network.
pass in on $int_if route-to \
{ ($ext_if1 $ext_gw1), ($ext_if2 $ext_gw2) } round-robin \
proto tcp from $lan_net to any flags S/SA modulate state
# load balance outgoing udp and icmp traffic from internal network
pass in on $int_if route-to \
{ ($ext_if1 $ext_gw1), ($ext_if2 $ext_gw2) } round-robin \
proto { udp, icmp } from $lan_net to any keep state

# general "pass out" rules for external interfaces
pass out on $ext_if1 proto tcp from any to any flags S/SA modulate state
pass out on $ext_if1 proto { udp, icmp } from any to any keep state
pass out on $ext_if2 proto tcp from any to any flags S/SA modulate state
pass out on $ext_if2 proto { udp, icmp } from any to any keep state

# route packets from any IPs on $ext_if1 to $ext_gw1 and the same for
# $ext_if2 and $ext_gw2
pass out on $ext_if1 route-to ($ext_if2 $ext_gw2) from $ext_if2 to any
pass out on $ext_if2 route-to ($ext_if1 $ext_gw1) from $ext_if1 to any

Тэгирование пакетов



  • Введение

  • Назначение тэгов пакетам

  • Проверка тэгов

  • Политика фильтрации

  • Тэггинг фреймов Ethernet


Введение



Тэггинг пакетов — способ пометить пакет внутренним идентификатором для дальнейшего использования в качестве критерия в правилах трансляции и фильтрации. С тэгированием становится возможным создание «доверия» между интерфейсами и определение, был ли пакет обработан правилами трансляции. Также становится возможным переход от фильтрации, основанной на правилах, к фильтрации, основанной на политиках.



Назначение тэгов пакетам



Тэг назначается пакету с использованием ключевого слова tag:

pass in on $int_if all tag INTERNAL_NET keep state

Тэг INTERNAL_NET будет назначен любому пакету, проходящему через это правило. Обратите внимание при использовании keep state; тегирование пакетов должно происходить в правилах pass.



Использование тэгов также допустимо и в макросах:

name = "INTERNAL_NET"
pass in on $int_if all tag $name keep state

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

  • $if — интерфейс
  • $srcaddr — IP адрес источника

  • $dstaddr — IP адрес назначения

  • $srcport — порт источника

  • $dstport — порт назначения

  • $proto — протокол

  • $nr — номер правила


Эти макросы определяются во время загрузки, а не во время выполнения.



Тегирование подчиняется следующим правилам:

  • Тэг «приклеивается». Только один тэг может быть прикреплен к пакету и он не может быть удален. Хотя есть возможность изменить его другим тэгом.

  • См. правило выше, пакет может содержать тэг, даже если последнее правило для пакета не содержало ключевое слово tag.

  • Одновременно тэгу назначается только один тэг.

  • Тэг — это внутренний идентификатор. Он не может быть послан во внешний мир.


Возьмем следующий набор правил для примера:

(1) pass in on $int_if tag INT_NET keep state
(2) pass in quick on $int_if proto tcp to port 80 tag \
INT_NET_HTTP keep state
(3) pass in quick on $int_if from 192.168.1.5 keep state


  • Пакет поступает на интерфейс $int_if и ему назначается тэг INT_NET в правиле #1.

  • TCP пакет направляется с $int_if на порт 80 куда то там в Интернет и будет одарен тэгом INT_NET по правилу #1. Но правилом #2 ему будет назначен тэг INT_NET_HTTP.

  • Пакет, поступивший с $int_if от адреса 192.168.1.5 будет пропущен правилом #3, так как это последнее соответствующее правило. Однако, пакеты TCP port 80 будут отмечены тэгом INT_NET_HTTP, а все остальные — тэгом INT_NET.


В дополнение к применению тэгов в правилах фильтрации, nat, rdr и binat есть возможность выполнять проверку уже установленных тэгов.



Проверка тэгов


Для проверки уже установленных тэгов используется ключевое слово tagged:

pass out on $ext_if tagged INT_NET keep state

Пакеты, уходящие на $ext_if должны быть помечены тэгом INT_NET, чтобы соответствовать правилу, приведенному выше. Существует возможность инверсного использования правила с помощью !:

pass out on $ext_if tagged ! WIFI_NET keep state

Политика фильтрации



Фильтрация пакетов на основе политик несколько отличается от фильтрации на основе правил. В политиках устанавливаются правила, по которым определенный вид трафика должен быть пропущен, а определенный — запрещен. Пакеты классифицируются внутри политик на основе традиционных критериев — IP адрес источника/назначения, протокола и т.д.



Для примера, рассмотрим следующую политику:

  • Трафик из внутренней сети в DMZ пропускается (LAN_DMZ)

  • Трафик из Интернет к серверу в DMZ пропускается (INET_DMZ)

  • Трафик из Интернет, переадресованный на spamd(8) пропускается (SPAMD)


Весь прочий трафик — блокируется Обратите внимание, что политика охватывает весь трафик, который будет проходить через систему сетевой защиты. В круглых скобках указан назначаемый для данного пункта политики тэг.

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

rdr on $ext_if proto tcp from <SPAMD> to port smtp tag SPAMD -> 127.0.0.1 port 8025

block all
pass in on $int_if from $int_net tag LAN_INET keep state
pass in on $int_if from $int_net to $dmz_net tag LAN_DMZ keep state
pass in on $ext_if proto tcp to $www_server port 80 tag INET_DMZ keep
state

Теперь правила, определяющие политику установлены.

pass in quick on $ext_if tagged SPAMD keep state
pass out quick on $ext_if tagged LAN_INET keep state
pass out quick on $dmz_if tagged LAN_DMZ keep state
pass out quick on $dmz_if tagged INET_DMZ keep state

Теперь, когда правила политики определены, необходимо определить и модифицировать классифицирующие правила. Для примера, если в DMZ добавляется сервер POP3/SMTP, необходимо добавить классифицирующее правило для POP3 и SMTP трафика, подобно нижеприведенному:

mail_server = "192.168.0.10"
...
pass in on $ext_if proto tcp to $mail_server port { smtp, pop3 } \
tag INET_DMZ keep state

Почтовый трафик теперь будет пропускаться, как соответствующий политике INET_DMZ.


Полный набор теперь будет выглядеть так:

# macros
int_if = "dc0"
dmz_if = "dc1"
ext_if = "ep0"
int_net = "10.0.0.0/24"
dmz_net = "192.168.0.0/24"
www_server = "192.168.0.5"
mail_server = "192.168.0.10"

table <SPAMD> persist file "/etc/spammers"

# classification -- classify packets based on the defined firewall
# policy.
rdr on $ext_if proto tcp from <SPAMD> to port smtp tag SPAMD -> 127.0.0.1 port 8025

block all
pass in on $int_if from $int_net tag LAN_INET keep state
pass in on $int_if from $int_net to $dmz_net tag LAN_DMZ keep state
pass in on $ext_if proto tcp to $www_server port 80 tag INET_DMZ keep state
pass in on $ext_if proto tcp to $mail_server port { smtp, pop3 } tag INET_DMZ keep state

# policy enforcement -- pass/block based on the defined firewall policy.
pass in quick on $ext_if tagged SPAMD keep state
pass out quick on $ext_if tagged LAN_INET keep state
pass out quick on $dmz_if tagged LAN_DMZ keep state
pass out quick on $dmz_if tagged INET_DMZ keep state

Тэггинг фреймов Ethernet



Тэгирование может быть выполнено на уровне Ethernet, если машина, осуществляющая тэггинг/фильтрацию, работает в режиме bridge(4). Для создания bridge(4) правил фильтрации используется ключевое слово tag. В PF существует возможность выполнять фильтрацию базируясь на mac адресе источника/назначения. Bridge(4) правила могут быть созданы с использованием команды brconfig(8):

# brconfig bridge0 rule pass in on fxp0 src 0:de:ad:be:ef:0 tag USER1

И затем в pf.conf указать:

pass in on fxp0 tagged USER1

Термины, используемые переводчиком.


Таблица состояний — таблица, образованная правилами Keep State и хранящая информацию о соединениях, образованных с помощью этого правила.


скинут/отброшен — dropped/rejected


Поднабор — Sub ruleset


Якорь — anchor


[ad name=»Google Adsense»]



 Уважайте труд автора, сохраняйте копирайты.
Реклама на сайте висит не просто так и если статья Вам понравилась, с ее помощью Вы можете отблагодарить автора за проделанную работу. Спасибо!

4 комментария в Пакетный фильтр OpenBSD, часть 2

  1. Да, по нелепой случайности статья «Пакетный фильтр OpenBSD, часть 2» была опубликована не полностью. Поправил.

  2. Большое Вам спасибо за статьи! Очень грамотно и доходчиво!

  3. Если трафик соответствует записи, но пересекает интерфейс указанный в ней, то соответствия не произойдет.
    If traffic matches a state table entry but is not crossing the interface recorded in that state entry, the match is rejected

    ЧТО то кажется не так.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

*