Пакетная фильтрация с помощью OpenBSD PF

Опубликовано – 10.01.2010

Автор:Peter N. M. Hansteen
Перевод:Сгибнев Михаил

Перед тем, как мы начнем

 Примечание переводчика. Первый перевод этой лекции появился в 2005 году. С тех пор данный материал пополнился новыми главами и несколько видоизменился. Приятного прочтения.

 Эта лекция[1] будет о системах сетевой защиты и связанных с ними функциях. Она начнется с небольшого рассмотрения теоретических вопросов и будет содержать в себе массу практических примеров фильтрации пакетов и управления трафиком. Как и в подавляющем большинстве других действий человека, решения приведенных задач могут быть достигнуты разными способами. Но сначала, хочу указать следующее:

 Это не HOWTO

 Этот документ не может выступать в качестве готового рецепта для копипастинга.

 Дабы укрепить дух свой — повторите Заповедь Сетевого Администратора:

  Это — моя сеть.
  Она дает мне работу и кормит меня
  Это моя ответственность
  И я забочусь о ней со всем тщанием
  Есть много других сетей, таких как моя
  Но нет ни одной точно такой же
  Я торжественно клянусь
  Что я не буду бессмысленно вставлять рецепты из HOWTO

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

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

 Ну а теперь можно перейти к основной теме нашей беседы.

 Примечание: [1] Этот документ является несколько преработанной версией лекции (если перевести с норвежского) «Эта лекция — о системах сетевой защиты и связанных с ними вопросах, с примерами из реальной жизни На основе пакетного фильтра PF проекта OpenBSD. Данный пакетный фильтр предлагает использование систем защиты сетей, трансляцию сетевых адресов (Network Address Translation), управление трафиком и управление полосой пропускания в единственной, гибкой и дружественной администратору системе. Питер надеется, что лекция даст вам некоторые идеи о том, как управлять вашим сетевым трафиком, решая все стоящие перед вами задачи. »

 Выражаю благодарность Roll Aarseth, David Snyder, Peter Postma, Henrik Kramshoj, Vegard Engen, Greg Lehey, Ian Darwin, Daniel Hartmeier, Mark Uemura, Hallvor Engen и прочим, чьи имена я не узнаю, пока не сделаю grep в своем почтовом ящике.

PF?

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

 Подсистема OpenBSD’s Packet Filter, которую большинство называет просто ‘PF’, первоначально была написана в режиме ошпаренной кошки летом/осенью 2001 года Даниэлем Хартмеиром и многими другими разработчиками OpenBSD, и вошла в состав системы OpenBSD 3.0 в декабре 2001.

 Потребность в новой подсистеме пакетной фильтрации возникла после того, как Даррен Рид объявил, что IPFilter, который в тот момент был глубоко интегрирован в OpenBSD, изменил лицензию с BSD. Сама лицензия была почти дословной копией лицензии BSD, за исключением права делать изменения в коде и распространения результата. Версия OpenBSD IPFilter содержала множество изменений и настроек, которые не соответствовали новой лицензии. IPFilter был удален из дерева исходных текстов OpenBSD 29-ого мая 2001 и на несколько недель система не имела функций пакетной фильтрации. (Прим. переводчика: после исключения из OpenBSD, ИМХО, IPFilter оказался в забвении чуть менее, чем полностью)

 К счастью, в Швейцарии, Даниэль Хартмеир уже делал некоторые эксперименты по ковырянию в сетевом коде ядра.

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

 IPFilter был выпилен из исходного дерева 29-ого мая. Первый коммит кода PF произошел в воскресенье, 24 июня 2001 в 19:48:58 UTC. [1]

 Последовало несколько месяцев довольно интенсивной работы, после чего версия PF, которая будет выпущена с OpenBSD 3.0, содержала довольно законченную реализацию пакетного фильтра, включая NAT.

 Если взглянуть со стороны, то Даниэль Хартмеир и другие разработчики PF хорошо использовали их опыт с кодом IPFilter. Как бы то нибыло, Даниэль сделал доклад на 2002 USENIX с тестами производительности, на которых показано, что OpenBSD 3.1 PF, работает под нагрузкой не хуже, а то и лучше IPFilter на той же самой платформе или iptables на Linux.

 Кроме того, некоторые тесты были выполнены на оригинальном PF от OpenBSD 3.0. Эти тесты показывали главным образом увеличение производительности версии 3.1 над версией 3.0. Статья Даниэля Хартмеира, раскрывающая подробности, доступна на сайте http://www.benzedrine.cx/pf-paper.html.

 Я не видел актуальные тесты, но как показывает мой личный опыт, PF не создает большой нагрузки на систему.

 Примечание:[1] Стоит заметить, что эпизод с нарушением авторского права IPFilter побудил группу OpenBSD выполнить ревизию лицензий всего дерева исходных текстов и портов, чтобы избежать подобных ситуаций в будущем. Много потенциальных проблем были раскрыты и решены за последующие месяцы, удалено много потенциальных ловушек лицензии. Тео де Рээдт подвел итоги усилий в сообщении к списку рассылки openbsd-misc 20-ого февраля 2003 года

Пакетный фильтр? Система сетевой защиты?

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

 PF работает в мире, который состоит из пакетов, протоколов, подключений и портов.

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

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

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

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

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

NAT?

 Другой вещью, о которой мы будем говорить довольно много, являются ‘внутренние’ и ‘внешние’ адреса, т.н. ‘routable’ и ‘non-routable’ адреса. Это, основа, не связанная непосредственно с системами сетевой защиты или фильтрацией пакетов, но из-за сложившейся мировой практики, мы должны будем затронуть этот вопрос.

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

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

 Когда произошла коммерциализация Интернет, фактически появились миллионы маленьких, недорогих машин, желающих подключиться к сети. Этот вид разработки показывал каждому признаку продолжения и даже ускорения. Поэтому было разработано решение, основанным на большем адресном пространстве — это было IP version 6, или IPv6 для краткости — который использует адреса на 128 битов. Это определялось как долгосрочное решение. Также я упомяну, что поддержку IPv6 встраивают OpenBSD по умолчанию, и PF имеет, насколько я знаю, поддержку IPv6 [1].

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

 Трафик с адреса, принадлежащего «non routable» диапазону не маршрутизируется в Интернет.

 Этот механизм называется «Network Address Translation», также известный как «IP masquerade» Он определяется двумя RFC, датированными 1994 и 1996 соответственно (RFC 1631, «The IP Network Address Translator (NAT)», dated May 1994 and RFC 1918, «Address Allocation for Private Internets», dated February 1996.).

 Может быть много причин использовать так называемый «RFC 1918 addresses», но традиционно и исторически главная причина состояла в том, что реальные адреса не доступны или использование их не практично.

PF сегодня

 В этом пункте мы подведем некоторые итоги. С 2001 года прошло несколько лет и PF в его существующей реализации OpenBSD, версии 4.4, является пакетным фильтром, способным к выполнению довольно многих вещей.

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

 И даже если NAT не является необходимой частью пакетного фильтра, по практическим причинам, хорошо, что логика перезаписи адреса расположена где-нибудь поблизости. Следовательно, PF также содержит и логику NAT.

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

 Прежде, чем был написан PF, OpenBSD уже содержал код ALTQ, для обработки балансировки загрузки и формирование трафика. Спустя некоторое время, altq был интегрирован с PF. Главным образом по практическим причинам.

 В результате этого все те особенности стали доступны для вас через один единственный, чрезвычайно удобный для чтения файл конфигурации, который обычно называют pf.conf, расположенный в каталоге /etc.

 PF теперь доступен как часть основной системы OpenBSD, на FreeBSD, где PF, начиная с версии 5.3, — один из трех систем защиты сетей, которые могут быть загружены по желанию, в NetBSD и DragonFlyBSD. Последние две операционных системы лично мной не изучались. В использовании PF на различных ОС есть незначительные специфические моменты, в зависимости от версии и типа ОС.

BSD vs Linux — конфигурация

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

 Сетевые интерфейсы в BSD, в отличие от Linux, не именуются как eth0, eth1 и т.д. Интерфейсам назначаются имена, исходя из названия драйвера плюс порядковый номер, например, платы 3Com, используя драйвер xl, будут видны как xl0, xl1. братите внимание на то, что может использоваться разный драйвер для плат одного производителя, например Intel может выглядеть как em0 так и fxp. Между различными BSD возможны отличия в именовании драйверов.[1]

 В процессе начальной загрузки, BSD системы читают конфигурацию из файла /etc/rc.conf, в котором указываются ссылки на загрузочные скипты, расположенные в /etc/rc. OpenBSD рекомендует использовать /etc/rc.conf.local для локальных настроек, так как rc.conf содержит значения по умолчанию, в то время как FreeBSD использует /etc/defaults/rc.conf, для хранения настроек по умолчанию, а в /etc/rc.conf используется для локальных настроек.

 Конфигурирование PF осуществляется путем внесения изменений в файл /etc/pf.conf, или с помощью утилиты pfctl. Утилита pfctl обладает большим количеством опций, некоторые из которых мы рассмотрим.

 Если вам интересно. то имеются как графические утилиты для управления PF, так и web-интерфейс, но они не входят в комплект поставки системы.

 Примечание:[1] Если вас гложут сомнения, обратитесь к выводу команды dmesg.

Простейшая из возможных установок (OpenBSD)

 Наконец, мы подошли к некоторым практическим шагам. В данном случае, мы будем иметь дело с единственной машиной, подключенной к Интернет.

 Для запуска PF необходимо дать указание системе rc. Для этого, в OpenBSD, необходимо добавить следующую строку в /etc/rc.conf.local:

pf=YES # enable PF

 Очень просто. Если есть желание указать путь к файлу конфигурации, то добавьте:

pf_rules=/etc/pf.conf # specify which file contains your rules

 По умолчанию используется файл /etc/pf.conf. PF будет запущен после перезагрузки. Файл конфигурации /etc/pf.conf, который идет в поставке OpenBSD, FreeBSD или NetBSD, содержит много полезных правил, но все они закомментированы.

 Если желания перезагрузиться у вас отсутствует, то можно воспользоваться утилитой pfctl.

peter@skapet:~$ sudo pfctl -ef /etc/pf.conf

 Таким образом мы запустим PF и загрузим наши наборы правил [1][2]. Так как правил никаких мы не писали, то и PF ничего фактически не делает.

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

 Этот заданный по умолчанию набор правила был спроектирован как мера безопасности в том случае, если на вашем шлюзе допущена ошибка в основном файле конфигурации. Это позволит вам получить доступ к системе и исправить содеянное. Заданный по умолчанию набор правил позволяет работать с основным набором служб: ssh отовсюду, DNS и NFS.

 На некоторых ранних версиях PF, используемых другими ОС, набора правил по умолчанию может не быть.

 Примечание:[1] Используйте sudo в повседневной деятельности! В OpenBSD он идет в поставке системы, в других Ос доступен как порт или пакет.

 [2] pfctl способен обработать несколько операций за раз.

Простейшая из возможных установок (FreeBSD)

 На FreeBSD действий может оказаться несколько больше. Добавьте следующие строки в файл /etc/rc.conf, предварительно прочитав главу PF chapter HandBook, так как у разных версий могут быть отличия.

pf_enable="YES" # Enable PF (load module if required)
pf_rules="/etc/pf.conf" # rules definition file for PF
pf_flags="" # additional flags for pfctl startup
pflog_enable="YES" # start pflogd(8)
pflog_logfile="/var/log/pflog" # where pflogd should store the logfile
pflog_flags="" # additional flags for pflogd startup

 К счастью почти все они уже присутствуют как настройки по умолчанию в вашем /etc/defaults/rc.conf, и только строки

pf_enable="YES" # Enable PF (load module if required)
pflog_enable="YES" # start pflogd(8)

 фактически должны присутствовать в /etc/rc.conf.

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

sudo kldload pf
sudo pfctl -e

 После этого можно управлять состоянием PF командами:

$ sudo /etc/rc.d/pf start
$ sudo /etc/rc.d/pf stop

Скрипт pf rcNG также поддерживает несколько других операций. Однако стоит отмечить, что в этом пункте нами не устанавливались правила, что означает, что PF ничего фактически не делает.

Простейшая из возможных установок (NetBSD)

 На NetBSD 2.0 и более новых, PF доступен как загружаемый модуль ядра, который можно установить через систему пакетов пакеты как pkgsrc/security/pflkm или откомпилировать в непосредственно в ядро. В NetBSD 3.0 сделан шаг вперед и PF — часть основной системы.

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

pseudo-device pf # PF packet filter
pseudo-device pflog # PF log interface

 В /etc/rc.conf необходимо добавить:

lkm="YES" # do load kernel modules
pf=YES
pflogd=YES

 В случае, если был установлен модуль, то его загрузка выполняется командой:

$ sudo modload /usr/lkm/pf.o

 А запуск PF командой:

$ sudo pfctl -e

 Как вариант, можно использовать соответствующие rc скрипты:

$ sudo /etc/rc.d/pf
$ sudo /etc/rc.d/pflogd

 Для автоматической загрузки модуля, добавьте следующую строку в файл /etc/lkm.conf:

/usr/lkm/pf.o - - - - AFTERMOUNT

 Если все было сделано правильно, то теперь можно приступать к написанию правил. Если что-то пошло не так, обратитесь к руководству NetBSD.

Первый набор правил — одиночная машина

 Приведем пример самой простой настройки, для единственной машины, которая не будет предоставлять никакие внешние сервисы и которая будет подключена к некой сети, в т.ч. Интернет. Пока мы используем /etc/pf.conf, который будет выглядеть следующим образом:

block in all
pass out all keep state

 Таким образом мы запрещаем любой входящий трафик, разрешаем наш собственный трафик и сохраняем информацию о состоянии на наших подключений. Хранение информации о состоянии позволяет принимать обратный трафик тех подключений, которые мы инициализировали. Стоит отметить, что начиная с OpenBSD 4.1, по умолчанию, для разрешающих правил, информация о состоянии [1] сохраняется автоматически, таким образом эквивалентный набор правил в новой OpenBSD 4.1 еще более упростился:

# minimal rule set, OpenBSD 4.1 and newer keeps state by default
block in all
pass out all

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

$ sudo pfctl -ef /etc/pf.conf

 Примечание:[1] Фактически новое значение по умолчанию переписывается, чтобы сохранить флаги состояния S/SA, гарантируя, что только начальные пакеты SYN во время установки подключения создают запись о состоянии, что позволяет устранить некоторые ложные срабатывания.

Немного более строго

 Для большего ужесточения и структурирования правил, мы запретим весь трафик, разрешив только необходимые сервисы. Почему я рекомендую поступать именно так, вы можете прочитать в статье The Six Dumbest Ideas in Computer Security. Это даст нам возможность ввести в работу две из особенностей, которые делают PF таким замечательным инструментом — списки и макросы.

 Внесем некоторые изменения в /etc/pf.conf, начинающиеся с

block all

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

tcp_services = "{ ssh, smtp, domain, www, pop3, auth, pop3s }"
udp_services = "{ domain }"

 Здесь мы видим два момента — макросы могут оперировать со списками и понимают буквенное обозначение сервиса так же хорошо, как и цифровое указание номера порта, используемое сервисом. Соответствие портов буквенным обозначениям берется из файла etc/services. Таким образом, наш набор правил приобретает вид:

block all
pass out proto tcp to any port $tcp_services
pass proto udp to any port $udp_services

 Не забывайте указывать ключевое слово keep state в разрешающих правилах, если вы используете PF на OpenBSD версии ниже, чем 4.1

 В этом пункте некоторые из нас скажут, что UDP не может иметь состояние соединения, но PF все-таки может обрабатывать такие сессии. Когда вы спрашиваете DNS-сервер об имени домена, разумно предположить, что вы захотите получить ответ.

 После внесения изменений в pf.conf, необходимо перезагрузить правила:

peter@skapet:~$ sudo pfctl -f /etc/pf.conf

 В случае, если мы где-либо ошиблись, будет выведено соответствующее сообщения. Для более детального вывода необходимо использовать опцию -v.

 Если Вы произвели обширные изменения в своем наборе правил, вы, что вполне ожидаемо, проверить правила прежде, чем загрузить их. Команда, которая вам необходима доя этого, выглядит как pfctl -nf /etc/pf.conf. Где опция -n заставляет правила только интерпретироваться, не загружая правила. Это дает вам возможность исправить любые ошибки. При любых обстоятельствах, действовать будет последний загруженный набор правил, что позволит отключить PF или загрузить новый набор правил.

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

Получение статистики с помощью pfctl

 Если вы захотите проверить работу PF, или посмотреть некую статистику, то на помощь вам придет утилита pfctl. Данная программа может предложить широкий выбор статистической информации, для этого необходимо использовать синтаксис pfctl -s [тип_информации]. Нижеприведенный пример взят с моего домашнего шлюза:

peter@skapet:~$ sudo pfctl -s info
Status: Enabled for 17 days 00:24:58 Debug: Urgent

Interface Stats for ep0 IPv4 IPv6
Bytes In 9257508558 0
Bytes Out 551145119 352
Packets In
Passed 7004355 0
Blocked 18975 0
Packets Out
Passed 5222502 3
Blocked 65 2

State Table Total Rate
current entries 15
searches 19620603 13.3/s
inserts 173104 0.1/s
removals 173089 0.1/s
Counters
match 196723 0.1/s
bad-offset 0 0.0/s
fragment 22 0.0/s
short 0 0.0/s
normalize 0 0.0/s
memory 0 0.0/s
bad-timestamp 0 0.0/s
congestion 0 0.0/s
ip-option 28 0.0/s
proto-cksum 325 0.0/s
state-mismatch 983 0.0/s
state-insert 0 0.0/s
state-limit 0 0.0/s
src-limit 26 0.0/s
synproxy 0 0.0/s

 Первая строка говорит нам о том, что PF запущен и работает без продыху уже больше двух недель, что соответствует времени последнего обновления системы. Использование команды pfctl -s all предоставит более исчерпывающую информацию. Для получения дополнительных сведений по работе этой утилиты, воспользуйтесь man 8 pfctl.

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

 В нашем наборе правил отсутствует несколько важных вещей. Например, вы, вероятнее всего, захотите разрешить некоторые типы трафика ICMP и UDP.

 Несмотря на то, что имеются более безопасные средства передачи файлов, вам, скорее всего, придется разрешить порты, необходимые для работы ftp.

 Скоро мы вернемся к этому вопросу.

Простой шлюз и, при необходимости, NAT

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

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

Шлюз и направления in, out и on

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

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

 Если вам необходимо, чтобы компьютеры, расположенные в сети, подключенной к интерфейсу ep1 нашего шлюза могли передавать информацию в сеть, подключенную к интерфейсу ep0, то вам потребуется правило вида:

pass in inet proto tcp on ep1 from ep1:network to ep0:network port $ports keep state

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

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

 Чтобы разрешить пакетам пройти в другую сеть, необходимо добавить соответствующее правило, выглядящее подобным образом:

pass out inet proto tcp on ep0 from ep1:network to ep0:network port $ports keep state

 Эти правила будут работать, но не факт, что вы этим будете довольны.

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

pass inet proto tcp from ep1:network to any port $ports keep state

 Которое позволит вашей локальной сети выходить в Интернет и будет решать задачи антиспуфинга и нормализации пакетов (antispoof и scrub). Реализация данных функций, в данный момент, достаточно хороша и мы вернемся к ним позже. Отметьте пока себе тот факт, что для простых наборов правил связанные наборы in/out для интерфейса добавляют больше проблем, чем решений.

 Для занятого сетевого администратора, читаемый набор правил — более безопасный набор правил.

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

Какова ваша локальная сеть?

 Выше мы ввели обозначение interface:network. Это хороший пример мнемоники, но чуть далее мы укажем еще более удобочитаемый формат записи.

 Например, вы можете определить макрокоманду $localnet, первоначально определяемую как сеть, непосредственно подключенную к внутреннему интерфейсу вашего шлюза (ep1:network в примерах выше).

 В качестве альтернативы, вы можете изменить определение $localnet используя запись типа [адрес]/[маска], для обозначения сети, например 192.168.100.0/24 для подсети частных адресов IPv4 или fec0:dead:beef::/64 для диапазона IPv6.

 Если у вас есть потребность, то можно определить $localnet как список сетей. В любом случае, правило приобретет вид подобно такому:

pass inet proto tcp from $localnet to any port $ports keep state

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

Настройка

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

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

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

# sysctl net.inet.ip.forwarding=1

 При необходимости маршрутизации трафика IPv6, команда выглядит следующим образом:

# sysctl net.inet6.ip6.forwarding=1

 Для того, чтобы изменения сохранили свою силу после перезагрузки, необходимо добавить соответствующие строки в файл конфигурации. В OpenBSD и NetBSD таким файлом является /etc/sysctl.conf:

net.inet.ip.forwarding=1
net.inet6.ip6.forwarding=1

 В FreeBSD необходимо внести в файл /etc/rc.conf следующие изменения:

gateway_enable="YES" #for ipv4
ipv6_gateway_enable="YES" #for ipv6

 Действие этих команд одинаково во всех системах, в FreeBSD так же можно использовать и команду sysctl, но традиционно, все изменения вносятся в файл /etc/rc.conf.

 После того, как вы определитесь с сетевыми интерфейсами, возможно вы захотите разрешить входящий трафик, инициализированный машинами из внутренней сети. В Этом случае, /etc/pf.conf приобретет подобный вид [1]:

ext_if = "ep0" # macro for external interface - use tun0 for PPPoE
int_if = "ep1" # macro for internal interface
localnet = $int_if:network

# ext_if IP address could be dynamic, hence ($ext_if)

nat on $ext_if from $localnet to any -> ($ext_if)
block all
pass inet proto tcp from { lo0, $localnet } to any keep state

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

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

 Круглые скобки, окружающие последнюю часть правила NAT — ($ext_if), необходимы для того, чтобы компенсировать возможность, что IP адрес внешнего интерфейса может быть назначен динамически. Их наличие гарантирует, что ваш трафик будет обработан без особых проблем даже в случае изменеия внешнего адреса.

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

client_out = "{ ftp-data, ftp, ssh, domain, pop3, auth, nntp, http, https, 446, cvspserver, 2628, 5999, 8000, 8080 }"

 Совместно с правилом:

pass inet proto tcp from $localnet to any port $client_out flags S/SA keep state

 Указанный набор портов может не соответствовать вашим потребностям, но мне он вполне подходит.

 Кроме того, у нас есть несколько других разрешающих правил и к наиболее интересным их них мы вскоре обратимся. Одим из полезных для нас правил является возможность удаленного доступа к нашему шлюзу по ssh:

pass in inet proto tcp from any to any port ssh

 Или так:

pass in inet proto tcp from any to $ext_if port ssh

 Можете использовать любой вариант на ваш выбор. Теперь нам необходимо разрешить сервисы UDP, в данном случае DNS и NTP. Макрос:

udp_services = "{ domain, ntp }"

 И соответствующее правило:

pass quick inet proto { tcp, udp } to any port $udp_services keep state

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

 Примечание [1] PPP соединения, к которым относится как Dial-UP так и GPRS и PPPoE (несмотря на то, что данный тип подключения работает через среду Ethernet), обозначаются как интерфейс tun0.

Старый грустный FTP

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

  • Пароли передаются в открытом виде
  • Требуется подключение по двум разным портам (управление и данные) в пределах одной сессии
  • Когда соединение установлено, порт передачи данных выбирается случайным образом

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

 В настоящее время есть более надежные, удобные и безопасные способы передачи файлов, например sftp или scp. Настоящий админ должен использовать их
вместо FTP.

 Но, вне зависимости от нашего желания, нам придется время от времени сталкиватся с FTP. В этом случае, вся наша работа будет заключаться в перенаправлении трафика от FTP сервера на маленькую программу, написанную специально для этой цели.

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

 Примечание переводчика. В случае, если вы счастливый обладатель OpenBSD 3.8 или, более младшей версии, то обратитесь к оригиналу статьи, разделу FTP through NAT: ftp-proxy. Я же продолжу перевод с рассмотрения новых версий.

ftp-proxy, новый стиль

 Данная глава предназначена для пользователей OpenBSD 3.9 и выше, или соответствующих эквивалентов.

 Как и у предыдущей версии, вся настройка ftp-proxy заключается в копировании нужных кусков из man страницы.

 В случае, если вы обновлялись с предыдущей версии, то исключите ftp-proxy из файла конфигурации inetd.conf и перезапустите inetd (если данный сервис вам не был нужен ни за чем другим, то его можно и вовсе остановить).

 Теперь вносим изменения в /etc/rc.conf.local или /etc/rc.conf:

ftpproxy_flags=""

 Если у вас есть такое желание, то можете запустить процесс вручную, командой /usr/sbin/ftp-proxy.

 Откройте pf.conf и добавьте два якоря в раздел поределений NAT:

nat-anchor "ftp-proxy/*"
rdr-anchor "ftp-proxy/*"

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

rdr pass on $int_if proto tcp from any to any port ftp -> 127.0.0.1 port 8021

 Перейдя вниз, к правилам фильтрации, добавьте якорь:

anchor "ftp-proxy/*"

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

pass out proto tcp from $proxy to any port 21 keep state

 Где $proxy является адресом сервера, на котором запущен демон.

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

 Если вы хотите защитить с помощью PF свой сервер, то используйте утилиту ftp-proxy в реверсном режиме (используя опцию -R )

Делаем нашу сеть проще для диагностики

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

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

 Даже когда вы мирно путешествуете по Интернету, маршрутизаторы обмениваются между собой ICMP сообщениями, например такими, как path MTU discovery.

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

 Одной из таких операционных систем был продукт компании Microsoft. Если вы воспользуетесь вашим любимым поисковиком, то обнаружите достаточно много материала по такой проблеме, как ‘ping of death’. В настоящее время подразумевается, что в сетевом коде всех систем было произведено достаточное количество изменений, чтобы решить эту проблему.

 В связи с такими проблемами, администраторам приходилось блокировать ICMP, по крайней мере ICMP ECHO, что сказывалось на работе утилиты ping.

Ну, тогда пропускаем ICMP?

 Своевременным вопосом будет — если ICMP такая хорошая вещь, то стоит ли его разрешить? Ответ — да, стоит.

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

pass inet proto icmp from any to any

 Из всего разнообразия типов пакетов стоит разрешить лишь некоторые, вам необходимые. Примечание переводчика: лично я разрешаю пакеты unreachable, packet-too-big, echo-reply, echo.

Простое решение проблемы

 Самым простым решением данной проблемы будет разрешить всем ICMP пакетам покидать вашу сети и разрешить прием таких пакетов на шлюзе:

pass inet proto icmp icmp-type $icmp_types from $localnet to any keep state
pass inet proto icmp icmp-type $icmp_types from any to $ext_if keep state

 Прием ICMP пакетов на шлюзе хорошее дело, но рассмотрим несколько моментов, показывающих нам гибкость PF.

Пропускаем ping

 У разработанного нами ранее набора правил есть очень большой недостаток, который заключается в том, что утилиты ping и traceroute не будут работать. Возможно, что для большинства пользователей вашей сети это не актуально, но вы себе можете здорово облегчить жизнь, указав макрос:

icmp_types = "echoreq"

 И соответствующее ему правило:

pass inet proto icmp all icmp-type $icmp_types keep state

 Если у вас возникнет желание разрешить другие типы пакетов, то вы всегда можете дополнить макрос icmp_types.

Пропускаем traceroute

 Другой необходимейшей программой, если ваши пользователи кричат, что недоступен Интернет, является traceroute. По умолчанию, Unix traceroute использует UDP протокол, определяя используемые порты согласно формуле. Ниже указано правило, позволяющее пользоваться командой traceroute всем unix-системам, включая GNU/Linux:

# allow out the default range for traceroute(8):
# "base+nhops*nqueries-1" (33434+64*3-1)
pass out on $ext_if inet proto udp from any to any port 33433 >< 33626 keep state

 Данное решение было обнаружено в списке рассылки openbsd-misc и я хотел бы порекомендовать вам его как источник ценнейшей информации по OpenBSD и PF.

Path MTU discovery

 Последнее, о чем я бы хотел вам рассказать в плане диагностики, это 'path MTU discovery'. Протоколы Internet создавались максимально независящими от конкретных устройств, поэтому довольно часто возникает проблема определения оптимального размера пакета. Параметр, ограничивающий размер пакета, обычно называют Maximum Transmission Unit, или MTU, и он определяет размер пакетов, обрабатываемых интерфейсом. Посмотреть MTU для сетевых интерфейсов вашего шлюза можно с помощью команды ifconfig.

 В ходе проводимых улучшений протоколов TCP/IP был разработан механизм, позволяющий определять MTU с помощью пакетов, у которых установлен флаг 'Do not fragment' и последующим анализом возвращенного ICMP пакета. В случае получения пакета "type 3, code 4", считается, что предел достигнут. Данный тип сообщает нам о недоступности адресата ("destination unreachable") по причине необходимости фрагментации при установленном DF-бите ("fragmentation needed, but the do not fragment flag is set"). После полученной информации имеет смысл изменить список пропускаемых типов ICMP:

icmp_types = "{ echoreq, unreach }"

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

pass inet proto icmp all icmp-type $icmp_types keep state

 Вместо разрешения всех кодов можно указать только "code 4":

pass inet proto icmp all icmp-type unreach code needfrag keep state

 PF способен фильтровать все типы ICMP и если вы хотите более предметно изучить этот вопрос, обратитесь к справочным руководствам man icmp(4) и icmp6(4). Фундаментальные основы вы можете найти в RFC792, RFC950, RFC1191, RFC1256, RFC2521, rfc2765, ICMP для IPv6 рассматривается в RFC1885, RFC2463, RFC2466.

Сетевая гигиена: block-policy, нормализация и так далее

 block-policy

 block-policy - это опция, которая может быть задана как часть набора правил и предшествует правилам перенаправления и фильтрации. Эта опция определяет какое действие будет произведено при получении запроса от удаленного хоста на порт, на котором в настоящее время не поднят ни один сервис. Возможны два действия - отбросить пакет без каких либо уведомлений или вернуть код состояния типа "Connection refused or similar". Немало копий было сломано на тему "подоконник должен быть вровень со стеной или выступать?". Мы хотим чтобы выступал - ответ отправлять мы будем.

set block-policy return

 Нормализация

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

scrub in all

 Некоторые службы, такие как NFS, требуют некоторых определенных опций обработки фрагмента. Более подробную информацию можно посмотреть в соответствующей странице man pf.conf.

 Антиспуфинг

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

 Укажем, что мы хотим блокировать такой трафик как из внешней сети, так и из внутренней, хотя его появление там маловероятно:

antispoof for $ext_if
antispoof for $int_if

 Блокировка немаршрутизируемых адресов извне

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

martians = "{ 127.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12, \
10.0.0.0/8, 169.254.0.0/16, 192.0.2.0/24, \
0.0.0.0/8, 240.0.0.0/4 }"

block drop in quick on $ext_if from $martians to any
block drop out quick on $ext_if from any to $martians

 Здесь макрос martians включает сети, указанные в RFC 1918 и некоторых других, не предназначенные для маршрутизации в Интернет.
 В зависимости от конфигурации вашей сети, данный список может изменяться.
 В завершение, мы рассмотрим NAT для маленькой сети.

Размещаем внутри сети почтовый и web-сервер

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

 Механизм перенаправления в PF делает публикацию сервисов довольно простым занятием. Предположим, что мы хотим предоставить доступ клиентам на наш веб-сервер по портам http и https, и кроме того, мы хотим организовать почтовый сервер, который посылает и получает электронную почту. В связи с этим мы можем добавить к уже имеющимся правилам примерно следующее:

webserver = "192.168.2.7"
webports = "{ http, https }"
emailserver = "192.168.2.5"
email = "{ smtp, pop3, imap, imap3, imaps, pop3s }"

rdr on $ext_if proto tcp from any to $ext_if port $webports -> $webserver
rdr on $ext_if proto tcp from any to $ext_if port $email -> $emailserver

pass proto tcp from any to $webserver port $webports flags S/SA synproxy state
pass proto tcp from any to $emailserver port $email flags S/SA synproxy state
pass proto tcp from $emailserver to any port smtp flags S/SA synproxy state

 Обратите внимание на флаг 'synproxy' в новых правилах. Он означает, что PF обработает установку подключения (трехстороннее рукопожатие) от имени вашего сервера или клиента перед тем, как передать пакет приложению. Это обеспечивает некоторую защиту против определенных типов атак.

 Наборы правил для конфигураций, в которых присутствует DMZ и служб, работающих на альтернативных портах, будут отличаться не очень сильно.

 Приводим в порядок внутреннюю часть

 Всё вышеуказанное хорошо работает в случае, когда запросы на ваши сервера поступают от внешних клиентов.

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

 Кратко упомянем их:

  • 'Split horizon' DNS - разделение зон на внутреннюю и внешнюю
  • Проксирование с помощью стороннего ПО, например nc(NetCat)
  • Обработка локальных сетей как специальный случай NAT. Мы рассмотрим эту опцию ниже.
  • Организация специальной сети 'DMZ', где располагаются сервера. Это потребует минимальных изменений в конфигурации правил 'DMZ'

 Таким образом, нам необходимо перехватывать пакеты из локальной сети, передать их удаленному сервису и вернуть ответ строго по назначению.

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

rdr on $int_if proto tcp from $localnet to $ext_if port $webports -> $webserver
rdr on $int_if proto tcp from $localnet to $ext_if port $email -> $emailserver
no nat on $int_if proto tcp from $int_if to $localnet
nat on $int_if proto tcp from $localnet to $webserver port $webports -> $int_if
nat on $int_if proto tcp from $localnet to $emailserver port $email -> $int_if

 В данном случае нет необходимости в каких-либо разрешающих правилах.

Таблицы, упрощающие нашу жизнь

 К этому моменту вы можете начать думать о том, что наш набор правил стал статичным и негибким. В конце концов будут некоторые виды данных, которые относятся к фильтрации и перенаправлению, но не могут быть помещенными в файл конфигурации! Совершенно верно, не PF предлагает механизмы для обработки таких ситуаций. Одним из таких механизмов являяется написание таблиц. Таблицы, в первую очередь, полезны как место хранения списков IP-адресов, которыми можно управлять, не перезагружая весь набор правил. Названия таблицы всегда включаются в угловые скобки < >.

table { 192.168.2.0/24, !192.168.2.5 }

 В данном примере, вся сеть 192.168.2.0/24 является частью таблицы, за исключением адреса 192.168.2.5, что обозначено с помощью оператора ! (логическое НЕ). Также существует возможность загружать таблицы из файлов, где каждый элемент находится в отдельной строке, например, как в файле /etc/clients:

192.168.2.0/24
!192.168.2.5

 Который, в свою очередь, используется для инициализации таблицы в /etc/pf.conf:

table persist file "/etc/clients"

 Теперь, для примера, изменим одно из написанных нами ранее правил:

pass inet proto tcp from to any port $client_out flags S/SA keep state

 Что позволит управлять исходящим трафиком с клиентских хостов. Вы можете управлять содержимым таблицы в реальном времени, например:

$ sudo pfctl -t clients -T add 192.168.1/16

 Учтите, что данные изменения произойдут только в оперативной памяти шлюза и не переживут перезагрузки. Вы можете сохранять содержимое таблиц на диск используя cron, с помощью команды типа pfctl -t clients -T show >/etc/clients. Также вы можете непосредственно изменить файл /etc/clients и скопировав его в память, заменить прежнее содержимое таблицы:

$ sudo pfctl -t clients -T replace -f /etc/clients

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

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

Логирование

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

set loginterface $ext_if

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

pass out log from to any port $email label client-email keep state

 В этом случае мы получим бинарный файл, который пригоден только для того, чтобы подать его на вход утилиты tcpdump. Обратите внимание на то, что здесь логируется только пакет, установивший соединение. Если вы хотите регистрировать весь трафик, соответствующий данному правилу, то используйте ключевое слово log (all). В реализации OpenBSD 3.7 и более ранних, используется ключевое слово log-all

 Раздел label создает набор счетчиков для подсчета статистики в этом правиле. Это может быть весьма удобно, если вы выставляете счет, например, за использование полосы пропускания.

 Также стоит отметить, что начиная с OpenBSD 4.1, интерфейс pflog может быть клонирован, поэтому их можно создать столько, сколько вам необходимо. В то же самое время был расширен синтаксис логирования правил, что позволило создавать правила на основе pflog.

pass log (all, to pflog2) inet proto tcp from $mailserver to any port smtp

 Вышеприведенным правилом мы регистрируем весь исходящий SMTP-трафик с $mailserver на интерфейс pflog2.

 Просмотр логирования с помощью tcpdump

 Как только вы включили логирование на одном или нескольких правилах, PF начинает их отслеживать через интерфейс pflog0, сохраняя бинарные файлы в файле /var/log/pflog. Данный журнал может быть вам полезен при последубщем просмотре информации или конвертации ее в другой формат. Однако, если вы хотите смотреть трафик в режиме реального времени, то вы можете использовать утилиту tcpdump и интерфейс pflog0.

 Вывод будет выглядеть примерно так:

peter@skapet:~$ sudo tcpdump -n -e -ttt -i pflog0
tcpdump: WARNING: pflog0: no IPv4 address assigned
tcpdump: listening on pflog0, link-type PFLOG
Feb 16 16:43:20.152187 rule 0/(match) block in on ep0: 194.54.59.189.2559 >
194.54.107.19.139: [|tcp] (DF)
Feb 16 16:48:26.073244 rule 27/(match) pass in on ep0: 61.213.167.236 >
194.54.107.19: icmp: echo request
Feb 16 16:49:09.563448 rule 0/(match) block in on ep0: 61.152.249.148.80 >
194.54.107.19.55609: [|tcp]
Feb 16 16:49:14.601022 rule 0/(match) block in on ep0: 194.54.59.189.3056 >
194.54.107.19.139: [|tcp] (DF)
Feb 16 16:53:10.110110 rule 0/(match) block in on ep0: 68.194.177.173 >
194.54.107.19: [|icmp]
Feb 16 16:55:54.818549 rule 27/(match) pass in on ep0: 61.213.167.237 >
194.54.107.19: icmp: echo request
Feb 16 16:57:55.577782 rule 27/(match) pass in on ep0: 202.43.202.16 >
194.54.107.19: icmp: echo request
Feb 16 17:01:27.108404 rule 0/(match) block in on ep0: 194.54.59.189.4520 >
194.54.107.19.139: [|tcp] (DF)
Feb 16 17:11:02.137310 rule 0/(match) block in on ep0: 222.73.4.154.80 >
194.54.107.19.55609: [|tcp]
Feb 16 17:14:05.739403 rule 0/(match) block in on ep0: 194.54.174.246.3970 >
194.54.107.19.135: [|tcp] (DF)
Feb 16 17:14:08.715163 rule 0/(match) block in on ep0: 194.54.174.246.3970 >
194.54.107.19.135: [|tcp] (DF)
Feb 16 17:14:09.308355 rule 0/(match) block in on ep0: 194.54.174.246.3970 >
194.54.107.19.135: [|tcp] (DF)
Feb 16 17:19:01.853730 rule 27/(match) pass in on ep0: 203.84.214.5 >
194.54.107.19: icmp: echo request

 В PF User Guide есть раздел, посвященный логированию. Вооружившись этими знаниями и утилитой tcpdump вы будете способны извлечь практически любые логи.

 Другие утилиты

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

 Отдельного упоминания заслуживают pfflowd, конвертирующий логи PF в формат Cisco NetFlow™ и pfstat, собирающий статистику от PF и рисующий графики.

 Знайте меру

 Если вкратце, то воздержитесь от правила:

block log all

 В PF User Guide имеется детальное руководство, как конвертироваль лог-файл PF в человекочитаемый формат с помощью syslog. Но если вы начнете бездумно и весело логировать абсолютно все пакеты, то вскоре вам не хватит дискового пространства.

Отслеживаем трафик с помощью pftop

 В самом названии утилиты pftop содержится намек на ее функционал. Данная утилита выводит на консоль мгновенное состояние открытых сессий и объемов пропущенного трафика.

pfTop: Up State 1-21/67, View: default, Order: none, Cache: 10000 19:52:28

PR DIR SRC DEST STATE AGE EXP PKTS BYTES
tcp Out 194.54.103.89:3847 216.193.211.2:25 9:9 28 67 29 3608
tcp In 207.182.140.5:44870 127.0.0.1:8025 4:4 15 86400 30 1594
tcp In 207.182.140.5:36469 127.0.0.1:8025 10:10 418 75 810 44675
tcp In 194.54.107.19:51593 194.54.103.65:22 4:4 146 86395 158 37326
tcp In 194.54.107.19:64926 194.54.103.65:22 4:4 193 86243 131 21186
tcp In 194.54.103.76:3010 64.136.25.171:80 9:9 154 59 11 1570
tcp In 194.54.103.76:3013 64.136.25.171:80 4:4 4 86397 6 1370
tcp In 194.54.103.66:3847 216.193.211.2:25 9:9 28 67 29 3608
tcp Out 194.54.103.76:3009 64.136.25.171:80 9:9 214 0 9 1490
tcp Out 194.54.103.76:3010 64.136.25.171:80 4:4 64 86337 7 1410
udp Out 194.54.107.18:41423 194.54.96.9:53 2:1 36 0 2 235
udp In 194.54.107.19:58732 194.54.103.66:53 1:2 36 0 2 219
udp In 194.54.107.19:54402 194.54.103.66:53 1:2 36 0 2 255
udp In 194.54.107.19:54681 194.54.103.66:53 1:2 36 0 2 271

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

 Данная программа не находится непосредственно в системе и требует установки из системы портов. Вероятно, это произошло потому, что всю эту информацию можно получить пользуясь только pfctl. Данная утилита доступна в системе портов OpenBSD и FreeBSD как sysutils/pftop, на NetBSD через систему pkgsrc как sysutils/pftop.

 
Примечание переводчика: с тем же результатом можно воспользоваться командой systat states, которая идет в комплекте с системой

Невидимый шлюз - мост

 Мостом. в нашем контексте, является машина с двумя и более сетевыми интерфейсами, расположенная межу Интернет и одной или несколькими внутренними сетями, при этом на сетевые интерфейсы машины не назначены IP адреса. Если в качестве операционной системы используется OpenBSD или подобная ей, то такая машина в состоянии фильтровать и переадресовывать трафик. Преимуществом такой системы является сложность в нападении на саму систему сетевой защиты. Недостатком является то, что все задачи администрирования должны выполняться с консоли машины, если вы не используете для этого специальный сетевой интерфейс или COM-порт/

 Методика настройки моста имеет свои особенности в зависимости от используемой операционоой системы. В случае OpenBSD, данный процесс выглядит так:

/etc/hostname.ep0
up

/etc/hostname.ep1
up

/etc/bridgename.bridge0
add ep0 add ep1 blocknonip ep0 blocknonip ep1 up

/etc/pf.conf
ext_if = ep0
int_if = ep1
interesting-traffic = { ... }
block all
pass quick on $ext_if all
pass log on $int_if from $int_if to any port $interesting-traffic keep state

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

 Кроме того, утилита brconfig из состава OpenBSD, предлагает собственный набор функций фильтрации, в дополнение к уже имеющимся. Для получения дополнительной информации обратитесь к страницам руководства bridge(4) и brconfig(8).

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

Управление трафиком с помощью ALTQ

 ALTQ - сокращение от ALTernate Queueing, является очень гибким механизмом для управления трафиком. До интеграции с PF, ALTQ был отдельной надстройкой.

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

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

 Очереди создаются на основе некой стратегии. По умолчанию, без использования ALTQ, используется FIFO (first, in first out).

 Очереди базируются на классах(CBQ), что на практике означает определение полосы пропускания очереди как количество данных в секунду или процентах и указание приоритета . Приоритеты могут иметь значение от 0 до 7 для cbq очередей и от 0 до 15 для priq очередей, Чем выше значение, тем выше приоритет. Упрощенный синтаксис выглядит следующим образом:

altq on interface type [options ... ] main_queue { sub_q1, sub_q2 ..}
queue sub_q1 [ options ... ]
queue sub_q2 [ options ... ]
[...]
pass [ ... ] queue sub_q1
pass [ ... ] queue sub_q2

 Если Вы будете использовать эти возможности в собственных наборах правил, вы должны при любых обстоятельствах прочитать страницу руководства man pf.conf и руководство пользователя PF. Эти документы содержат очень детальное и доходчивоее объяснение синтаксиса.

Приоритезация трафика с помощью ALTQ

 Мы переходим к другому примеру, взятому из сети Дэниела Хартмеира. Подобно довольно многим из нас, Дэниел подключен по ADSL , и естественно он хотел бы использовать полосу пропускания более эффективно.

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

 Анализ данных показал, что пакеты ACK для каждого пакета переданных данных вызвали непропорционально большое замедление, возможно из-за очереди FIFO (First In, First Out) в исходящем трафике. То есть, складывалась ситуация, когда запросы на новые пакеты проходили не самым оптималным способом.

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

ext_if="kue0"

altq on $ext_if priq bandwidth 100Kb queue { q_pri, q_def }
queue q_pri priority 7
queue q_def priority 1 priq(default)

pass out on $ext_if proto tcp from $ext_if to any flags S/SA keep state queue (q_def, q_pri)

pass in on $ext_if proto tcp from any to $ext_if flags S/SA keep state queue (q_def, q_pri)

 В результате работа канала действительно улучшилась.

Итак, почему это работает?

 Причина находится в том, как код ALTQ обрабатывает подочереди с различными приоритетами. Как только подключение попало в основную очередь, ALTQ просматривает каждый пакет типа сервиса (ToS). Пакеты ACK имеют значение бита ToS Delay равное 'low', что как бы говорит нам о желании отправителя побыстрее доставить данный пакет.

 Когда ALTQ видит пакет low delay и имеются очереди различных приоритетов, то он назначит пакет в очередь с более высоким приоритетом. Это означает, что пакеты ACK пропускаются перед очередью с низким приоритетом, что ведет к более быстрой их доставке получателю.

 Статья Даниэля, посвященная данному вопросу, доступна на его сайте по адресу http://www.benzedrine.cx/ackpri.html.

ALTQ - процентное распределение

 Теперь приведем пример из жизни. Очереди установлены на внешнем интерфейсе. Это, по всей видимости обычный подход, так как ограничения на полосу пропускания на внешнем интерфейсе более неблагоприятны. Хотя принципе, очереди распределения полосы и балансировки трафика можут быть сделаны на любом сетевом интерфейсе. В этом примере правила включают в себя cbq очередь для полной полосы пропускания 640 КБ с шестью sub очередями.

altq on $ext_if cbq bandwidth 640Kb queue { def, ftp, udp, http, ssh, icmp }
queue def bandwidth 18% cbq(default borrow red)
queue ftp bandwidth 10% cbq(borrow red)
queue udp bandwidth 30% cbq(borrow red)
queue http bandwidth 20% cbq(borrow red)
queue ssh bandwidth 20% cbq(borrow red) { ssh_interactive, ssh_bulk }
queue ssh_interactive priority 7
queue ssh_bulk priority 0
queue icmp bandwidth 2% cbq

 Мы видим, что определенной в качестве очереди по умолчанию назначено 18 процентов полосы пропускания, в нее будет направляться весь трафик, не подходящий под остальные очереди. Ключевые слова borrow и red подразумевают, что очередь может 'заимствовать' полосу пропускания от родительской очереди, при этом перегрузка канала обрабатывается с помощью алгоритма RED (Random Early Detection). Другие очереди следуют более или менее тому же образцу, за исключением очереди ssh, которая имеет две дочерние очереди с индивидуальными приоритетами.

 Наконец, правила, в которых указывается, какой трафик назначен в очереди и критерии попадания:

pass log quick on $ext_if proto tcp from any to any port 22 flags S/SA keep state queue (ssh_bulk, ssh_interactive)
pass in quick on $ext_if proto tcp from any to any port 20 flags S/SA keep state queue ftp
pass in quick on $ext_if proto tcp from any to any port 80 flags S/SA keep state queue http
pass out on $ext_if proto udp all keep state queue udp
pass out on $ext_if proto icmp all keep state queue icmp

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

ALTQ - обработка нежелательного трафика

 Наш последний пример использования altq родился или в момент одного из многих вирусных штормов или под влиянием нескончаемого потока спама. Не секрет, что большинство машин, рассылающих вирусы и спам, находятся под управлением ОС Windows. У PF есть довольно надежный механизм определения операционной системы, пытающейся установить соединение, что и было применено одним из пользователей OpenBSD:

altq on $ext_if cbq queue { q_default q_web q_mail }

queue q_default cbq(default)
queue q_web (...)

## all mail limited to 1Mb/sec
queue q_mail bandwidth 1Mb { q_mail_windows }
## windows mail limited to 56Kb/sec
queue q_mail_windows bandwidth 56Kb

pass in quick proto tcp from any os "Windows" to $ext_if port 25 keep state queue q_mail_windows
pass in quick proto tcp from any to $ext_if port 25 label "smtp" keep state queue q_mail

 В данном примере, всему почтовому трафику назначена полоса пропускания в один мегабит, в то время как почтовый трафик, принимаемый от машин под управлением Windows, использует полосу пропускания в 56 Кб/с. Неудивительно, что общая загрузка канала снизилась, что сопровождалось злым хихиканьем.

CARP и pfsync

 CARP и pfsync - это два новшеcтва, появившиеся в OpenBSD 3.5. CARP - сокращение от Common Address Redundancy Protocol. Он был разработан как альтернатива VRRP (Virtual Router Redundancy Protocol, RFC 2281, RFC 3768), который был весьма близок к стандартизации IETF.

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

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

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

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

 Более подробно о CARP я расскажу в ближайшем будущем. Для получения дополнительной информации обратитесь к документации OpenBSD, руководствам man и домашней странице Рьяна Макбрайд http://www.countersiege.com/doc/pfsync-carp/

Работа с беспроводными сетями

 Хочу сказать, что в общем случае при использовании BSD-систем и при работе с OpenBSD в частности, настройка беспроводного соединения мало чем отличается от обычного проводного. Большая часть появляющихся проблем связана с тем, что мы имеем дело с радиоволнами, а не с проводами. Перед тем, как перейти к практическим вопросам, рассмотрим несколько теоретических аспектов.

 Маленькое уточнение для IEEE 802.11

 Переход к беспроводным сетям позволяет нам по новому взглянуть на безопасность передачи данных. Рассмотрим два основных механизма обеспечения безопасности, входящих в IEEE 802.11. Для получения более полной информации по вопросу обеспечения безопасности беспроводных сетей, обратитесь к документам http://www.kjhole.com, wifinetnews.com и The Unofficial 802.11 Security Web Page.

 Их наличие позволяет нам не прибегать к использованию SSH или SSL при передаче наших данных.

 WEP (Wired Equivalent Privacy)

 Одним из побочных эффектов использования радиоволн является возможность их легкого перехвата. Разработчики семейства протоколов 802.11 об этом факте догадывались и поэтому придумали решение, названное как Wired Equivalent Privacy или WEP.

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

 WPA (WiFi Protected Access)

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

Настраиваем простейшую беспроводную сеть

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

ath0 at pci1 dev 4 function 0 "Atheros AR5212" rev 0x01: irq 11
ath0: AR5212 5.6 phy 4.1 rf5111 1.7 rf2111 2.3, ETSI1W, address
00:0d:88:c8:a7:c4

 Затем нам нужно настроить TCP/IP. В случае использования OpenBSD, необходимо внести следующие изменения в файл /etc/hostname.ath0:

up media autoselect mediaopt hostap mode 11b chan 6 nwid unwiredbsd nwkey 0x1deadbeef9
inet 10.168.103.1

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

 При работе с FreeBSD, вам необходимо было бы добавить эти строки в файл /etc/start_if.ath0, при необходимости изменить наименование интерфейса.

 Если вы хотите использовать dhcpd для назначения адресов и других сетевых параметров клиентам, то строки в файле /etc/hostname.ath0 будут выглядеть следующим образом.

up media autoselect mode 11b chan 6 nwid unwiredbsd nwkey 0x1deadbeef9
dhcp

 В случае FreeBSD, эти строки помещаются в файл /etc/start_if.ath0.

 Для организации NAT беспроводного интерфейса, необходимо внести небольшие изменения в файл /etc/pf.conf:

air_if = "ath0"
nat on $ext_if from $air_if:network to any -> ($ext_if) static-port

 Также вам потребуется внести изменения в конфигурацию ftp-proxy и добавить $air_if в разрешающие правила.

 В принципе, это минимально необходимые действия для получения точки доступа

Открытая, но защищенная с помощью authpf, беспроводная сеть

 Как обычно, есть и другие способы настройки безопасности вашей беспроводной сети, отличные от того, который мы только что видели.

 Другой подход был описан моим другом, Вегардом Эндженом, который рассказал мне, что он установил authpf. authpf является пользовательской оболочкой, которая позволяет вам загружать правила PF на основании имени пользователя.

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

 Загружаемые правила касаются только IP адреса, с которого вошел в систему пользователь и применяются ровно столько времени, сколько длятся ssh сессия. Как только сессия завершается пользователем, правила выгружаются и запрещаетя весь трафик, кроме ssh с данного IP адреса.

 Ниже приведен пример конфигурации. В данном случае WEP не используется, возлагая решение проблем безопасности на PF и authpf:

 Начинается всё с создания файла /etc/authpf/authpf.conf. Наличие этого файла необходимо для работы authpf, но он может быть пустой.

 Далее мы вносим изменения в /etc/pf.conf. Во первых, добавим определение интерфейсов:

int_if="sis1"
ext_if="sis0"
wi_if = "wi0"

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

auth_web="192.168.27.20"

 Таблица authpf:

table persist

 Правила NAT можно сделать частью authpf.rules, но мы разместим их в основном pf.conf:

nat on $ext_if from $wi_if:network to any -> ($ext_if)

 Указываем правила перенаправления для обеспечения доступа к серверам, находящимся в локальной сети. Их также можно разместить в authpf.rules, но так как без разрешающих правил они ни на что не повлияют, то мы разместим их в основном pf.conf:

rdr on $wi_if proto tcp from any to $myaddr port $tcp_in -> $server
rdr on $wi_if proto udp from any to $myaddr port $udp_in -> $server

 Следующее правило пошлет весь трафик от неавторизованных пользователей на 80 порт сервера $auth_web. Это может быть сервер, отображающий контактную информацию для людей, обнаруживших данную беспроводную сеть или сервер, обрабатывающий кредитные карты и создающий логины для подключения к сети.

rdr on $wi_if proto tcp from ! to any port 80 -> $auth_web

 Для активации nat, binat или redirects в authpf:

nat-anchor "authpf/*"
binat-anchor "authpf/*"
rdr-anchor "authpf/*"

 Правила фильтрации начинаются, как всегда, с:

block all

 Также здесь находятся другие глобальные, не зависящие от пользователей, правила. Здесь же мы удостоверяемся, что неавторизованным пользователям разрешен доступ на сервер $auth_web:

anchor "authpf/*" in on wi0

pass in on $wi_if inet proto tcp from any to $auth_web port 80 keep state

 Разрешаем на беспроводном интерфейсе работу сервисов DNS, DHCP и SSH:

pass in on $wi_if inet proto udp from any port 53 keep state
pass in on $wi_if inet proto udp from any to $wi_if port 67
pass in on $wi_if inet proto tcp from any to $wi_if port 22 keep state

 Определяем правила для всех пользователей, у которых в качестве оболочки установлен /usr/sbin/authpf. Эти правила находятся в файле /etc/authpf/authpf.rules:

int_if = "sis1"
ext_if = "sis0"
wi_if = "wi0"
server = "192.168.27.15"
myaddr = "213.187.n.m"

# Services which live on the internal network
# and need to be accessible
tcp_services = "{ 22, 25, 53, 80, 110, 113, 995 }"
udp_services = "{ 53 }"
tcp_in = " { 22, 25, 53, 80, 993, 2317, pop3}"
udp_in = "{ 53 }"

# Pass traffic to elsewhere, that is the outside world
pass in on $wi_if inet from to ! $int_if:network keep state

# Let authenticated users use services on
# the internal network.

pass in on $wi_if inet proto tcp from to $server port $tcp_in keep state
pass in on $wi_if inet proto udp from to $server port $udp_in keep state

# Also pass to external address. This means you can access
# internal services on external addresses.

pass in on $wi_if inet proto tcp from to $myaddr port $tcp_in keep state
pass in on $wi_if inet proto udp from to $myaddr port $udp_in keep state

 Таким образом мы имеем открытую сеть, где каждый может получить адрес по DHCP. Весь HTTP трафик от неавторизованных пользователей перенаправляется на 80 порт сервера 192.168.27.20. Разрешен досуп к шлюзу по 22 порту, при этом для пользователей прошедших авторизацию, загружаются правила согласно полученному по DHCP IP адресу. Мы можем применять более персональные настройки, помещая правила в файл /etc/authpf/users/$user/authpf.rules, при этом возможно использование макроса $user_ip для указания IP адреса пользователя. Например, если я хочу получить неограниченный доступ, то файл /etc/authpf/users/vegard/authpf.rules будет выглядеть следующим образом:

wi_if="wi0"
pass in on $wi_if from $user_ip to any keep state

Предотвращение подбора пароля

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

Sep 26 03:12:34 skapet sshd[25771]: Failed password for root from
200.72.41.31 port 40992 ssh2
Sep 26 03:12:34 skapet sshd[5279]: Failed password for root from
200.72.41.31 port 40992 ssh2
Sep 26 03:12:35 skapet sshd[5279]: Received disconnect from
200.72.41.31: 11: Bye Bye
Sep 26 03:12:44 skapet sshd[29635]: Invalid user admin from
200.72.41.31
Sep 26 03:12:44 skapet sshd[24703]: input_userauth_request:
invalid user admin
Sep 26 03:12:44 skapet sshd[24703]: Failed password for invalid user
admin from 200.72.41.31 port 41484 ssh2
Sep 26 03:12:44 skapet sshd[29635]: Failed password for invalid user
admin from 200.72.41.31 port 41484 ssh2
Sep 26 03:12:45 skapet sshd[24703]: Connection closed by 200.72.41.31
Sep 26 03:13:10 skapet sshd[11459]: Failed password for root from
200.72.41.31 port 43344 ssh2
Sep 26 03:13:10 skapet sshd[7635]: Failed password for root from
200.72.41.31 port 43344 ssh2
Sep 26 03:13:10 skapet sshd[11459]: Received disconnect from
200.72.41.31: 11: Bye Bye
Sep 26 03:13:15 skapet sshd[31357]: Invalid user admin from 200.72.41.31
Sep 26 03:13:15 skapet sshd[10543]: input_userauth_request: invalid
user admin
Sep 26 03:13:15 skapet sshd[10543]: Failed password for invalid user
admin from 200.72.41.31 port 43811 ssh2
Sep 26 03:13:15 skapet sshd[31357]: Failed password for invalid user
admin from 200.72.41.31 port 43811 ssh2
Sep 26 03:13:15 skapet sshd[10543]: Received disconnect from
200.72.41.31: 11: Bye Bye
Sep 26 03:13:25 skapet sshd[6526]: Connection closed by 200.72.41.31

 Подобные записи повторяются время от времени. Это и есть пример грубого перебора пароля, в надежде получить доступ на машину.

 Самым простым решением будет полная блокировка доступа в pf.conf, но это может привести к проблемам другого рода, типа предоставление доступа пользователям, которым это действительно необходимо. Можно перенести порт сервиса с традиционно используемого на другой, но это вряд-ли остановит опытного взломщика.

 Начиная с OpenBSD 3.7[1], PF поддерживает более элегантное решение. Вы можете написать разрешающее правило, указав ограничение на число одновременных подключений с одного хоста. Так же, хорошей мерой будет занесение хостов, превысивших лимит в черный список, подлежащий блокировке. Вот как это делается:

 Создаем таблицу:

table persist

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

block quick from

 А в заключение - разрешающее правило:

pass inet proto tcp from any to $localnet port $tcp_services flags S/SA keep state \
(max-src-conn 100, max-src-conn-rate 15/5, overload

 За исключением указанных в скобках параметров, всё выглядит достаточно знакомым, не правда ли?

 max-src-conn - число одновременных подключений с одного хоста. В данном примере 100, но, возможно, вы захотите изменить это значение.

 max-src-conn-rate - частота открытия новых соединений. В данном случае - 15 соединений в секунду.

 overload - таким образом мы добавляем IP-адреса хостов, превысивших данный лимит, к таблице

 flush global - в случае превышения лимита все сессии с данным хостом будут прерваны, при этом параметр global указывает на всю таблицу правил, а не только это правило.

 Эффект применения бесподобен. Теперь любой злой брутфорсер получит сообщение "Fatal: timeout before authentication" как только начнет свою вредоносную деятельность.

 Перед использованием подобных правил еще раз подумайте, соответствуют ли они политике вашей сети.

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

pass quick proto tcp from any to any port ssh flags S/SA keep state
(max-src-conn 15, max-src-conn-rate 5/3, overload flush global)

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

Приведение таблиц в порядок с помощью expiretable

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

 Для решения данной проблемы, Хенрик Густафсон написал expiretable, который удаляет записи в таблице, к которым не было обращений в течение установленного периода времени.

 Для примера, воспользуемся expiretable для удаления записей, старше чем 24 часа, в таблице . Для этого, внесите изменения в /etc/rc.local:

/usr/local/sbin/expiretable -v -d -t 24h bruteforce

 Начиная с OpenBSD 4.1, есть возможность очищать таблицы с помощью pfctl. Например, чтобы удалить все записи, на которые не ссылались в течении 86400 секунд, воспользуйтесь командой:

# pfctl -t bruteforce -T expire 86400

Тяжелое врямя для спамера

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

table persist
table persist
rdr pass on $ext_if inet proto tcp from to { $ext_if, $localnet } port smtp -> 127.0.0.1 port 8025
rdr pass on $ext_if inet proto tcp from ! to { $ext_if, $localnet } port smtp -> 127.0.0.1 port 8025

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

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

Вы не одни: черные списки

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

Черный и серый список

 Когда с spamd устанавливает соединение хост, находящийся в черном списке, то ему выдается баннер и происходит немедленное переключение в режим отправки сообщений SMTP по 1 байту. Таким образом отправителем впустую тратится огромное количество времени. Такой режим называют tarpitting.

 spamd также поддерживает работу с серыми списками, при этом начиная с OpenBSD 4.1 данный режим работы является режимом по умолчанию.

Настройка spamd

 Настройка spamd довольно проста. Вы просто конфигурируете файл spamd.conf, который обычно находится в каталоге /etc, но начиная с OpenBSD 4.1 переместился в /etc/mail. Сам файл прокомментирован довольно слабо, но дополнительную информацию можно почерпнуть на странице руководства man.

 Обратите внимание на то, что в FreeBSD spamd идет в виде порта, находящегося в mail/spamd, который необходимо установить. Так же, при использовании серых списков, вам понадобится файл descriptor file system (смотрите fdescfs(5)), примонтированного в /dev/fd/. Так же, стоит добавить следующую строку в /etc/fstab:

fdescfs /dev/fd fdescfs rw 0 0

Убедитесь, что fdescfs вкомпилирован в ядро системы или загружен модулем с использованием утилиты kldload.

 Самая первая строка, не начинающаяся с #, а следовательно, не являющаяся комментарием, содержит определение списка all, который, что понятно из его наименования, содержит полный перечень используемых списков.

all:\
:becks:whitelist:

 Здесь вы добавляете все черные списки, которые будете использовать, разделяя их двоеточиями. Если вы хотите использовать белые списки, то необходимо использовать ключевое слово whitelist сразу после имени списка, например :blacklist:whitelist:.

 Создадим определение черного списка:

becks:\
:black:\
:msg="SPAM. Your address %A has sent spam within the last 24 hours":\
:method=http:\
:file=www.openbsd.org/spamd/traplist.gz

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

 Определение белого списка задается аналогичным образом:

whitelist:\
:white:\
:method=file:\
:file=/etc/mail/whitelist.txt

 Поле msg не является обязательным.

 Используя идущий в составе системы по умолчанию spamd.conf вы рискуете заблокировать получение почты с весьма больших блоков адресов, включая несколько стран, таких как Корея. Советую вам внимательно отнестись к составлению списков.

 Внесите в файлы /etc/rc.conf или /etc/rc.conf.local строки запуска spamd:

spamd_flags="-v -G 2:4:864" # for normal use: "" and see spamd-setup(8)
spamd_grey=YES # use spamd greylisting if YES

 Еще раз упомяну, что начиная с версий OpenBSD 4.1 и выше, опция spamd_grey является лишней. Если вы хотите, чтобы spamd работал только в режиме черного списка без использования серых списков, то вы должны использовать опцию spamd_black.

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

 После завершения настройки и запуска spamd, необходимо создать задание cron для своевременного обновления таблиц. Как только таблицы заполнятся, их содержимое можно посмотреть с помощью pfctl. Если вы захотите изменить или удалить запись, то рекомендую использовать утилиту spamdb утилиту вместо команды pfctl. Я расскажу об этом чуть позже.

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

Практические советы по работе с spamd

 Что представляет собой spamd на практике? Нами spamd был запущен в работу в 2004 году, до этого использовалась связка spamassassin и clamav как часть процесса exim. На exim был настроен таким образом, чтобы помечать и доставлять сообщения с с баллами, назначенными spamassasin от 5 до 9.99, отбрасывая сообщения с баллами выше 10. Эффективность spamassassin, в связи с ростом нагрузки, со временем уменьшалась.

 После помещения spamd в работу, общее количество обработанных сообщений и число сообщений, обработанных spamassassin, значительно уменьшилось.

 Если вы запускаете spamd с опцией -v, то журнальные файлы начинают регистрировать дополнительную информацию, которая выглядит примерно так:

Oct 2 19:55:05 delilah spamd[26905]: (GREY) 83.23.213.115:
->
Oct 2 19:55:05 delilah spamd[26905]: 83.23.213.115: disconnected after
0 seconds.
Oct 2 19:55:05 delilah spamd[26905]: 83.23.213.115: connected (2/1)
Oct 2 19:55:06 delilah spamd[26905]: (GREY) 83.23.213.115:
->
Oct 2 19:55:06 delilah spamd[26905]: 83.23.213.115: disconnected after
1 seconds.
Oct 2 19:57:07 delilah spamd[26905]: (BLACK) 65.210.185.131:
->
Oct 2 19:58:50 delilah spamd[26905]: 65.210.185.131: From: Auto
lnsurance Savings
Oct 2 19:58:50 delilah spamd[26905]: 65.210.185.131: Subject: Start
SAVlNG M0NEY on Auto lnsurance
Oct 2 19:58:50 delilah spamd[26905]: 65.210.185.131: To: adm@dataped.no
Oct 2 20:00:05 delilah spamd[26905]: 65.210.185.131: disconnected after
404 seconds. lists: spews1
Oct 2 20:03:48 delilah spamd[26905]: 222.240.6.118: connected (1/0)
Oct 2 20:03:48 delilah spamd[26905]: 222.240.6.118: disconnected after
0 seconds.
Oct 2 20:06:51 delilah spamd[26905]: 24.71.110.10: connected (1/1),
lists: spews1
Oct 2 20:07:00 delilah spamd[26905]: 221.196.37.249: connected (2/1)
Oct 2 20:07:00 delilah spamd[26905]: 221.196.37.249: disconnected after
0 seconds.
Oct 2 20:07:12 delilah spamd[26905]: 24.71.110.10: disconnected after
21 seconds. lists: spews1

 В первых трех строках показано подключение, далее следует повторное подключение и подключение машины, чей адрес находится в черном списке. Заголовки (GREY) и (BLACK) показывают, по какому списку проходит соединение. По прошествии 404 секунд (или 6 минут, 44 секунды), хост, помещенный в черный список, сдается, не завершив доставку.

 В ходе эксплуатации spamd оказалось, что список spews2 (spews level 2) слишком широкий и от его использования отказались, не особо увеличив долю проходящего спама.

 Теперь представлю вам кульминацию моего опыта использования spamd. Журнальный файл зарегистрировал следующую запись:

Dec 11 23:57:24 delilah spamd[32048]: 69.6.40.26: connected (1/1),
lists: spamhaus spews1 spews2
Dec 12 00:30:08 delilah spamd[32048]: 69.6.40.26: disconnected
after 1964 seconds. lists: spamhaus spews1 spews2

 Это касается отправителя из wholesalebandwidth.com. Этот хост сделал 13 попыток доставить почту в период с 9-ого декабря до 12-ого декабря 2004. Последняя попытка продолжалась 32 минуты, 44 секунды, так и не завершившись успехом.

 При обновлении руководства я нашел несколько записей, в которых это значение было превышено:

peter@delilah:~$ grep disconnected /var/log/spamd | awk '{print $9}' \
| sort -rn | uniq -c | head
1 42673
1 36099
1 14714
1 10170
1 5495
1 3025
1 2193
1 1964
1 1872
1 1718

 Первое, в 42673 секунды, что составляет почти двенадцать часов,

Dec 21 14:22:44 delilah spamd[29949]: 85.152.224.147: connected (5/2)
Dec 21 14:22:46 delilah spamd[29949]: 85.152.224.147: connected (6/2)
Dec 21 14:22:47 delilah spamd[29949]: 85.152.224.147: disconnected
after 3 seconds.
Dec 22 02:13:59 delilah spamd[29949]: 85.152.224.147: disconnected
after 42673 seconds.

 Тут, очевидно, мы имеем дело с машиной, находящейся в сети испанского оператора, зараженной на редкость примитивным червем.

Еще немного: spamdb and greytrapping

 Очень слабо документированными и редкоупоминаемыми утилитами для облегчения процесса управления spamd являются spamdb database tool и spamlogd whitelist updater, причем обе предназначены для работы с серыми списками. При этом spamlogd работает в фоновом режиме, а spamdb может предложить много интересного.

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

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

 spamdb - основной интерфейс администратора для управления черными, серыми и белыми списками через наполнение базы данных /var/db/spamdb.

 Ранние версии spamdb просто предлагали опции для добавления белых списков к базе данных, обновления существующих (spamdb-a nn.mm.nn.mm) и удаления ненужных (spamdb-d nn.mm.nn.mm) для компенсации недостатков в ченых или серых списках.

 По прошествии времени, к релизу OpenBSD 3.8, появившемуся в первой половины 2005, разработчики и пользователи spamd накопили много опыта в анализе поведении спаммера и реакциях спаммера на контрмеры.

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

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

 Greytrapping представляет собой помещение IP-адреса хостов, не прошедших проверку, во временный черный список на 24 часа. Как показала практика, это не настолько большой срок, чтобы привести к ложным срабатываниям, при этом машины, продолжающие рассылать спам, очень быстро возвращаются в черный список.

Настройка traplist

 Для создания traplist необходимо использовать утилиту spamdb с опцией -Т. Например:

peter@delilah:~$ spamdb -T -a wkitp98zpu.fsf@datadok.no

 Спамеры думали, что за пару лет ничего не изменилось:

Nov 6 09:50:25 delilah spamd[23576]: 210.214.12.57: connected (1/0)
Nov 6 09:50:32 delilah spamd[23576]: 210.214.12.57: connected (2/0)
Nov 6 09:50:40 delilah spamd[23576]: (GREY) 210.214.12.57:
->
Nov 6 09:50:40 delilah spamd[23576]: 210.214.12.57: disconnected after 15 seconds.
Nov 6 09:50:42 delilah spamd[23576]: 210.214.12.57: connected (2/0)
Nov 6 09:50:45 delilah spamd[23576]: (GREY) 210.214.12.57:
->
Nov 6 09:50:45 delilah spamd[23576]: 210.214.12.57: disconnected after 13 seconds.
Nov 6 09:50:50 delilah spamd[23576]: 210.214.12.57: connected (2/0)
Nov 6 09:51:00 delilah spamd[23576]: (GREY) 210.214.12.57:
->
Nov 6 09:51:00 delilah spamd[23576]: 210.214.12.57: disconnected after 18 seconds.
Nov 6 09:51:02 delilah spamd[23576]: 210.214.12.57: connected (2/0)
Nov 6 09:51:02 delilah spamd[23576]: 210.214.12.57: disconnected after 12 seconds.
Nov 6 09:51:02 delilah spamd[23576]: 210.214.12.57: connected (2/0)
Nov 6 09:51:18 delilah spamd[23576]: (GREY) 210.214.12.57:
->
Nov 6 09:51:18 delilah spamd[23576]: 210.214.12.57: disconnected after 16 seconds.
Nov 6 09:51:18 delilah spamd[23576]: (GREY) 210.214.12.57:
->
Nov 6 09:51:18 delilah spamd[23576]: 210.214.12.57: disconnected after 16 seconds.
Nov 6 09:51:20 delilah spamd[23576]: 210.214.12.57: connected (1/1), lists: spamd-greytrap
Nov 6 09:51:23 delilah spamd[23576]: 210.214.12.57: connected (2/2), lists: spamd-greytrap
Nov 6 09:55:33 delilah spamd[23576]: (BLACK) 210.214.12.57:
->
Nov 6 09:55:34 delilah spamd[23576]: (BLACK) 210.214.12.57:
->

 Данный фрагмент журнального файла показывает нам, что машина, рассылающая спам была сначала добавлена в серый список, после чего попыталась изменить адрес отправителя и попала в spamd-greytrap, где и проведет больше 20 часов.

Удаление записей из traplist

 spamdb предлагает еще несколько опций о которых вы должны знать. Использование опции -T совместно с -d удалит запись о почтовом адресе из таблицы, а совместное использование опций -t (нижний регистр) с -a или -d позволяет добавлять или удалять IP-адреса

 Экспорт списка может быть сделан с помощью spamdb, grep и капельку воображения.

Обратная сторона: некоторые люди не получают письма

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

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

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

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

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

table file "/etc/mail/whitelist.txt"

 Для того, чтобы удостовериться, что SMTP трафик с этих адресов не попадает на spamd, необходимо добавить правило no rdr в первых строках правил перенаправления:

no rdr proto tcp from to $mailservers port smtp

 Как только вы сделали эти изменения в вашем наборе правил, вам необходимо создать файл whitelist.txt, затем перезагрузить набор правил, используя pfctl -f. После этого можно управлять таблицей как указано в главе Таблицы, упрощающие нашу жизнь.

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

Список используемой литературы

 OpenBSDs web http://www.openbsd.org/

 OpenBSDs FAQ, http://www.openbsd.org/faq/index.html

 PF User Guide http://www.openbsd.org/faq/pf/index.html

 Daniel Hartmeier's PF pages, http://www.benzedrine.cx/pf.html

 Daniel Hartmeier: Design and Performance of the OpenBSD Stateful Packet Filter (pf), http://www.benzedrine.cx/pf-paper.html (presented at Usenix 2002)

 Nate Underwood: HOWTO: Transparent Packet Filtering with OpenBSD, http://ezine.daemonnews.org/200207/transpfobsd.html

 Randal L. Schwartz: Monitoring Net Traffic with OpenBSD's Packet Filter, http://www.samag.com/documents/s=9053/sam0403j/0403j.htm

 Unix.se: Brandv?gg med OpenBSD, http://unix.se/Brandv%E4gg_med_OpenBSD

 Randal L. Schwartz: Blog for Thu, Jan 29, 2004, http://use.perl.org/~merlyn/journal/17094

 RFC 1631, "The IP Network Address Translator (NAT)", May 1994 http://www.ietf.org/rfc/rfc1631.txt?number=1631

 RFC 1918, "Address Allocation for Private Internets", February 1996 http://www.ietf.org/rfc/rfc1918.txt?number=1918

 The FreeBSD PF home page, http://pf4freebsd.love2party.net/

 Peter Postma's PF on NetBSD pages, http://nedbsd.nl/~ppostma/pf/

 Marcus Ranum: The Six Dumbest Ideas in Computer Security, September 1, 2005

 Kjell J?rgen Hole WiFi courseware, http://www.kjhole.com/Standards/WiFi/WiFiDownloads.html, also see wifinetnews.com; also The Unofficial 802.11 Security Web Page comes highly recommended.

 Greylisting.org greylisting.org is the home of all things greylisting, with links to numerous articles and other useful information.

 Evan Harris: The Next Step in the Spam Control War: Greylisting (the original greylisting paper)

 Peter N. M. Hansteen: The silent network: Denying the spam and malware chatter using free tools - paper presented at BSDCan 2007 which puts spamd into a slightly wider spam and malware fighting context along with some data on spammer behavior

 Peter N. M. Hansteen: The Book of PF, No Starch Press 2007, is an expanded and extensively rewritten followup to the tutorial, and covers a range of advanced topics in addition to those covered here.




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

4 комментария в Пакетная фильтрация с помощью OpenBSD PF

  1. Игорь:

    Огромный респект за Ваш труд, сразу видно что Вы через себя все пропустили вот теперь в голове ясность познания. БЛАГОДАРЮ

  2. Mixa:

    Смерть человекам! Слава роботам! Не за что 🙂

  3. code_310:

    спасибо большое за труд уже думал сам переводить.

  4. все как обычно:

    Спасибо за статью и в который раз разжеванный «старый» PF.

    Правда, гораздо большую ценность в настоящий момент представляет информация о существенных изменениях в PF, начиная с мая 2010 года, когда вышла версия OpenBSD 4.7.
    Это не критика, это предложение)

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

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

*