---
title: Глава 26. Межсетевые экраны
part: Часть IV. Сетевые коммуникации
prev: books/handbook/network-servers
next: books/handbook/advanced-networking
showBookMenu: true
weight: 31
params:
  path: "/books/handbook/firewalls/"
---

[[firewalls]]
= Межсетевые экраны
:doctype: book
:toc: macro
:toclevels: 1
:icons: font
:sectnums:
:sectnumlevels: 6
:sectnumoffset: 26
:partnums:
:source-highlighter: rouge
:experimental:
:images-path: books/handbook/firewalls/

ifdef::env-beastie[]
ifdef::backend-html5[]
:imagesdir: ../../../../images/{images-path}
endif::[]
ifndef::book[]
include::shared/authors.adoc[]
include::shared/mirrors.adoc[]
include::shared/releases.adoc[]
include::shared/attributes/attributes-{{% lang %}}.adoc[]
include::shared/{{% lang %}}/teams.adoc[]
include::shared/{{% lang %}}/mailing-lists.adoc[]
include::shared/{{% lang %}}/urls.adoc[]
toc::[]
endif::[]
ifdef::backend-pdf,backend-epub3[]
include::../../../../../shared/asciidoctor.adoc[]
endif::[]
endif::[]

ifndef::env-beastie[]
toc::[]
include::../../../../../shared/asciidoctor.adoc[]
endif::[]

[[firewalls-intro]]
== Введение

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

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

* Для защиты и изоляции приложений, сервисов и машин во внутренней сети от нежелательного трафика, приходящего из внешней сети интернет.
* Для ограничения или запрещения доступа хостов внутренней сети к сервисам внешней сети интернет.
* Для поддержки преобразования сетевых адресов (network address translation, NAT), что дает возможность задействовать во внутренней сети приватные IP адреса и совместно использовать одно подключение к сети Интернет (либо через один выделенный IP адрес, либо через адрес из пула автоматически присваиваемых публичных адресов).

После прочтения этой главы вы узнаете:

* Как правильно задать правила фильтрации пакетов.
* Разницу между межсетевыми экранами, встроенными в FreeBSD
* Как использовать и настраивать межсетевой экран OpenBSD PF.
* Как использовать и настраивать IPFILTER.
* Как использовать и настраивать IPFW.

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

* Ознакомиться с основами FreeBSD и интернет.

[[firewalls-concepts]]
== Принципы работы межсетевых экранов

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

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

[NOTE]
====
Если не указано иначе, то все приведенные в этом разделе примеры наборов правил и конфигураций относятся к типу включающего межсетевого экрана.
====

Безопасность может быть дополнительно повышена с использованием "межсетевого экрана с сохранением состояния". Такой межсетевой экран сохраняет информацию об открытых соединениях и разрешает только трафик через открытые соединения или открытие новых соединений. Недостаток межсетевого экрана с сохранением состояния в том, что он может быть уязвим для атак DoS (Denial of Service, отказ в обслуживании), если множество новых соединений открывается очень быстро. Большинство межсетевых экранов позволяют комбинировать поведение с сохранением состояния и без сохранения состояния, что позволяет создавать оптимальную конфигурацию для каждой конкретной системы.

[[firewalls-apps]]
== Пакеты межсетевых экранов

В базовую систему FreeBSD встроено три программных межсетевых экрана. Это _IPFILTER_ (известный также как IPF), _IPFIREWALL_ (известный также как IPFW) и _OpenBSD PacketFilter_ (также известный как PF). Помимо этого, FreeBSD содержит два пакета ограничения трафика (по существу, предназначенных для контроля пропускной способности сетевого соединения): man:altq[4] и man:dummynet[4]. Dummynet традиционно сильно связан с IPFW, а ALTQ с PF. В настоящее время IPFILTER не поддерживает ограничение пропускной способности сетевого соединения. Для реализации этой функции предлагается использовать IPFILTER совместно с одним из двух существующих пакетов ограничения трафика. Конфигурация следующая: IPFILTER задействуется для фильтрации и трансляции трафика, а IPFW с man:dummynet[4] _или_PF с ALTQ - для контроля пропускной способности сетевого соединения. IPFW и PF для контроля исходящих и входящих пакетов используют наборы правил, хотя и разными способами с разным синтаксисом правил.

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

Автор предпочитает IPFILTER, поскольку его правила с сохранением состояния гораздо проще использовать совместно с NAT; кроме того, в него встроен ftp прокси, что упрощает правила для фильтрации исходящих FTP соединений.

Поскольку все межсетевые экраны основаны на анализе значений выбранных полей заголовка пакета, для создания правил межсетевого экрана необходимо понимание принципов TCP/IP, того, что означают различные поля заголовка пакета, и как эти поля используются в обычной сессии. Хорошим примером является: http://www.ipprimer.com/overview.cfm[http://www.ipprimer.com/overview.cfm].

[[firewalls-pf]]
== Packet Filter (PF, межсетевой экран OpenBSD) и ALTQ

В июле 2003 программный межсетевой экран OpenBSD, известный как PF, был портирован в FreeBSD и стал доступен из коллекции портов FreeBSD; первым релизом, где PF был интегрирован в основную систему, стала FreeBSD 5.3 в ноябре 2004. PF это полноценный межсетевой экран с широким набором возможностей, в котором есть опциональная поддержка ALTQ (Alternate Queuing). ALTQ предоставляет управление пропускной способностью Quality of Service (QoS).

Проект OpenBSD осуществляет замечательную работу по поддержке http://www.openbsd.org/faq/pf/[PF FAQ]. Этот раздел руководства фокусируется на взаимосвязи PF и FreeBSD, предоставляя лишь общую информацию по его использованию. За более подробной информацией по использованию PF обратитесь к http://www.openbsd.org/faq/pf/[PF FAQ].

Дополнительные сведения о PF для FreeBSD можно получить с веб сайта: http://pf4freebsd.love2party.net/[http://pf4freebsd.love2party.net/].

=== Использование модуля ядра PF

Чтобы загрузить PF как модуль ядра, добавьте следующую строку в [.filename]#/etc/rc.conf#:

[.programlisting]
....
pf_enable="YES"
....

Далее, выполните стартовый скрипт:

[source,shell]
....
# /etc/rc.d/pf start
....

Учтите, модуль PF не загрузится, если он не сможет найти конфигурационный файл с набором правил. По умолчанию размещение файла с правилами следующее: [.filename]#/etc/pf.conf#. Если путь к файлу отличается от вышеприведённого, то внесите в [.filename]#/etc/rc.conf# строку вида:

[.programlisting]
....
pf_rules="/path/to/pf.conf"
....

Файл с примерами конфигураций [.filename]#pf.conf# находится в каталоге [.filename]#/usr/shared/examples/pf/#.

Модуль PF можно также загрузить вручную:

[source,shell]
....
# kldload pf.ko
....

Поддержка ведения логов для PF обеспечивается модулем `pflog.ko`, для загрузки которого добавьте следующую строку в [.filename]#/etc/rc.conf#:

[.programlisting]
....
pflog_enable="YES"
....

и запустите на выполнение скрипт:

[source,shell]
....
# /etc/rc.d/pflog start
....

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

=== Параметры ядра

Включение PF путем компиляции с ядром FreeBSD не является обязательным требованием, однако вам может понадобиться одна из функциональных возможностей, которая не включена в загружаемый модуль. Например, man:pfsync[4] являет собой псевдоустройство, которое вносит определенные изменения в таблицу состояний, используемую PF. В дальнейшем, это псевдоустройство может быть скомпоновано с man:carp[4] чтобы создать отказоустойчивую систему межсетевых экранов на основе PF. 

Пример параметров конфигурации ядра для включения PF находится в [.filename]#/usr/src/sys/conf/NOTES# и показан здесь:

[.programlisting]
....
device pf
device pflog
device pfsync
....

`device pf` включает поддержку межсетевого экрана "Packet Filter" (man:pf[4]).

`device pflog` включает необязательное сетевое псевдоустройство man:pflog[4], которое может использоваться для протоколирования трафика через man:bpf[4]. Даемон man:pflogd[8] может использоваться для сохранения протоколируемой информации на диск.

`device pfsync` включает необязательное сетевое псевдоустройство man:pfsync[4], используемое для отслеживания "изменений состояния".

=== Доступные параметры rc.conf

Для активации PF и man:pflog[4] во время загрузки в man:rc.conf[5] должны быть включены следующие переменные:

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

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

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

=== Создание правил фильтрации

Пакет PF читает конфигурацию из файла man:pf.conf[5] (полный путь: [.filename]#/etc/pf.conf#); пакеты отвергаются, пропускаются или модифицируются в соответствии с правилами и определениями из этого файла. В стандартную поставку FreeBSD входят несколько файлов с примерами конфигураций, которые находятся в каталоге [.filename]#/usr/shared/examples/pf/#. За исчерпывающим описанием правил PF обратитесь к http://www.openbsd.org/faq/pf/[PF FAQ].

[WARNING]
====

Изучая http://www.openbsd.org/faq/pf/[PF FAQ], имейте в виду, что различные версии FreeBSD могут содержать разные версии pf. В настоящий момент FreeBSD использует ту же версию PF, которая включена в OpenBSD 4.1.
====

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

=== Работа с PF

Для управления PF используйте утилиту man:pfctl[8]. Ниже приведено несколько полезных команд (все возможные команды и опции приведены на странице справочника man:pfctl[8]):

[.informaltable]
[cols="1,1", frame="none", options="header"]
|===
| Команда
| Действие

|`pfctl -e`
|Включить PF

|`pfctl -d`
|Выключить PF

|`pfctl -F all -f /etc/pf.conf`
|Сбросить все правила (NAT, правила фильтрации, состояния соединений, таблицы и т.д.) и загрузить новые с файла [.filename]#/etc/pf.conf#

|`pfctl -s [ rules \| nat \| state ]`
|Отобразить правила фильтрации, правила NAT или таблицу состояний соединений

|`pfctl -vnf /etc/pf.conf`
|Проверить [.filename]#/etc/pf.conf# на наличие ошибок, но сами наборы правил не загружать
|===

=== Включение ALTQ

ALTQ может быть включен только путем компилирования ядра FreeBSD с соответствующими параметрами. ALTQ поддерживается не всеми существующими драйверами сетевых карт. Для просмотра списка поддерживаемых устройств в вашем релизе FreeBSD обратитесь к странице справочника man:altq[4].

Следующие параметры включат ALTQ и добавят дополнительную функциональность.

[.programlisting]
....
options         ALTQ
options         ALTQ_CBQ        # Class Bases Queuing (CBQ)
options         ALTQ_RED        # Random Early Detection (RED)
options         ALTQ_RIO        # RED In/Out
options         ALTQ_HFSC       # Hierarchical Packet Scheduler (HFSC)
options         ALTQ_PRIQ       # Priority Queuing (PRIQ)
options         ALTQ_NOPCC      # Required for SMP build
....

`options ALTQ` включает подсистему ALTQ.

`options ALTQ_CBQ` включает _Class Based Queuing_ (CBQ). CBQ позволяет распределять пропускную способность соединений по классам или очередям для выставления приоритетов трафика на основе правил фильтрации.

`options ALTQ_RED` включает _Random Early Detection_ (RED). RED используется для предотвращения перегрузки сети. RED вычисляет длину очереди и сравнивает ее с минимальным и максимальным значением длины очереди. Если очередь превышает максимум, все новые пакеты будут отброшены. В соответствии со своим названием, RED отбрасывает пакеты из различных соединений в произвольном порядке.

`options ALTQ_RIO` включает _Random Early Detection In and Out_.

`options ALTQ_HFSC` включает _Hierarchical Fair Service Curve Packet Scheduler_. Дополнительная информация о HFSC находится по адресу: http://www-2.cs.cmu.edu/\~hzhang/HFSC/main.html[http://www-2.cs.cmu.edu/~hzhang/HFSC/main.html]. 

`options ALTQ_PRIQ` включает _Priority Queuing_ (PRIQ). PRIQ всегда первым пропускает трафик из очереди c более высоким приоритетом.

`options ALTQ_NOPCC` включает поддержку SMP для ALTQ. Эта опция необходима для SMP систем.

[[firewalls-ipf]]
== * IPFILTER (IPF)

[WARNING]
====

Перевод раздела не завершен.
====

[NOTE]
====
Этот раздел находится в процессе написания; содержание может не вполне соответствовать действительности.
====

Автором IPFILTER является Darren Reed. IPFILTER не зависит от операционной системы: это приложение с открытыми исходными текстами, которое было портировано на операционные системы FreeBSD, NetBSD, OpenBSD, SunOS(TM), HP/UX, и Solaris(TM). IPFILTER активно разрабатывается и поддерживается, регулярно выпускаются обновленные версии.

IPFILTER основан на межсетевом экране и механизме NAT уровня ядра, которые управляются и контролируются утилитами уровня пользовательских процессов. Правила межсетевого экрана могут устанавливаться или удаляться утилитой man:ipf[8]. Правила NAT могут устанавливаться или удаляться утилитой man:ipnat[1]. Утилита man:ipfstat[8] выводит статистику IPFILTER для ядра. Программа man:ipmon[8] может заносить действия IPFILTER в файлы системных протоколов.

IPF был первоначально написан с использованием правила "последнее совпадение применяется" и только с правилами без сохранения состояния. Со временем IPF был расширен и включает параметры "quick" и "keep state" (сохранение состояния), которые кардинальным образом изменяют логику обработки пакетов. Официальная документация IPF включает традиционные параметры правил с традиционной последовательностью обработки пакетов. Измененные функции включены в виде дополнительных параметров, они необходимы для создания эффективного межсетевого экрана.

Инструкции этого раздела подразумевают использование параметра "quick" и параметра сохранения состояния "keep state". Это основа для создания включающего межсетевого экрана.

Детальное описание традиционных методов обработки правил: http://www.obfuscation.org/ipf/ipf-howto.html#TOC_1[http://www.obfuscation.org/ipf/ipf-howto.html#TOC_1] и http://coombs.anu.edu.au/\~avalon/ip-filter.html[http://coombs.anu.edu.au/~avalon/ip-filter.html].

IPF FAQ находится по адресу http://www.phildev.net/ipf/index.html[http://www.phildev.net/ipf/index.html].

Архив списка рассылки по IPFilter с возможностью поиска доступен по адресу http://marc.theaimsgroup.com/?l=ipfilter[http://marc.theaimsgroup.com/?l=ipfilter].

=== Включение IPF

IPF включен в базовую систему FreeBSD в качестве отдельного загружаемого модуля. Система динамически загрузит модуль IPF, если в [.filename]#rc.conf# указана переменная `ipfilter_enable="YES"`. Модуль создается с включенным протоколированием и правилом по умолчанию `pass all` (пропускать все). Для изменения правила по умолчанию не обязательно собирать ядро с новыми параметрами. Просто добавьте в конец набора правило, блокирующее все пакеты.

=== Параметры ядра

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

Пример параметров настройки ядра для IPF находится в [.filename]#/usr/src/sys/conf/NOTES# и воспроизведен здесь:

[.programlisting]
....
options IPFILTER
options IPFILTER_LOG
options IPFILTER_DEFAULT_BLOCK
....

`options IPFILTER` включает поддержку межсетевого экрана "IPFILTER".

`options IPFILTER_LOG` включает протоколирование трафика через IPF путем записи его в псевдо-устройство протоколирования пакетов [.filename]#ipl# для каждого правила, содержащего ключевое слово `log`.

`options IPFILTER_DEFAULT_BLOCK` изменяет поведение по умолчанию так, что блокируется каждый пакет, не соответствующий правилу `pass`.

Эти настройки будут работать только после сборки и установки нового ядра.

=== Доступные параметры rc.conf

Для активации IPF во время загрузки в [.filename]#/etc/rc.conf# потребуется добавить следующие переменные:

[.programlisting]
....
ipfilter_enable="YES"             # Запуск межсетевого экрана ipf
ipfilter_rules="/etc/ipf.rules"   # Загрузка файла с правилами
ipmon_enable="YES"                # Включение протоколирования IP monitor
ipmon_flags="-Ds"                 # D = запуск в виде даемона
                                  # s = протоколирование в syslog
                                  # v = протоколирование tcp window, ack, seq
                                  # n = отображение имен IP и портов
....

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

[.programlisting]
....
gateway_enable="YES"              # Включение шлюза для локальной сети
ipnat_enable="YES"                # Запуск функции ipnat
ipnat_rules="/etc/ipnat.rules"    # Определение файла правил для ipnat
....

=== IPF

Команда man:ipf[8] используется для загрузки файла с правилами. Обычно создается файл, содержащий подготовленный набор правил, который полностью замещает набор, используемый на данный момент:

[source,shell]
....
# ipf -Fa -f /etc/ipf.rules
....

`-Fa` означает сброс всех внутренних таблиц правил.

`-f` указывает файл с правилами, который необходимо загрузить.

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

На странице справочной системы man:ipf[8] находится подробная информация по всем флагам этой команды.

Набор правил для команды man:ipf[8] должен быть в виде стандартного текстового файла. Правила, написанные в виде скрипта с символами подстановки, не принимаются.

Есть способ составления правил IPF, использующих символы подстановки. Обратитесь к <<firewalls-ipf-rules-script>>.

=== IPFSTAT

По умолчанию man:ipfstat[8] получает и отображает суммарную статистику, полученную в результате применения действующих правил к пакетам, проходящим через межсетевой экран с момента его последнего запуска, или с того момента, когда статистика была последний раз обнулена командой `ipf -Z`.

Детальная информация приводится на странице справочника man:ipfstat[8].

Вывод команды man:ipfstat[8] по умолчанию выглядит примерно так:

[source,shell]
....
input packets: blocked 99286 passed 1255609 nomatch 14686 counted 0
 output packets: blocked 4200 passed 1284345 nomatch 14687 counted 0
 input packets logged: blocked 99286 passed 0
 output packets logged: blocked 0 passed 0
 packets logged: input 0 output 0
 log failures: input 3898 output 0
 fragment state(in): kept 0 lost 0
 fragment state(out): kept 0 lost 0
 packet state(in): kept 169364 lost 0
 packet state(out): kept 431395 lost 0
 ICMP replies: 0 TCP RSTs sent: 0
 Result cache hits(in): 1215208 (out): 1098963
 IN Pullups succeeded: 2 failed: 0
 OUT Pullups succeeded: 0 failed: 0
 Fastroute successes: 0 failures: 0
 TCP cksum fails(in): 0 (out): 0
 Packet log flags set: (0)
....

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

`ipfstat -in` отображает правила, применяемые к входящим пакетам, вместе с номерами этих правил.

`ipfstat -on` отображает правила, применяемые к исходящим пакетам, вместе с номерами этих правил.

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

[source,shell]
....
@1 pass out on xl0 from any to any
@2 block out on dc0 from any to any
@3 pass out quick on dc0 proto tcp/udp from any to any keep state
....

`ipfstat -ih` отображает правила, применяемые к входящим пакетам, со счетчиком количества совпадений для каждого правила.

`ipfstat -oh` отображает правила, применяемые к исходящим пакетам, со счетчиком количества совпадений для каждого правила.

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

[source,shell]
....
2451423 pass out on xl0 from any to any
354727 block out on dc0 from any to any
430918 pass out quick on dc0 proto tcp/udp from any to any keep state
....

Одна из наиболее важных функций команды `ipfstat` активируется флагом `-t`, правила отображаются подобно тому, как man:top[1] показывает таблицу запущенных процессов FreeBSD. Когда межсетевой экран подвергается атаке, эта функция позволяет обнаружить соответствующие пакеты. Дополнительные флаги дают возможность выбирать IP адрес назначения или источника, порт или протокол, которые будут отслеживаться в реальном времени. Подробная информация приведена на странице man:ipfstat[8].

=== IPMON

Для того, чтобы стало возможно использование команды `ipmon`, необходимо включить параметр ядра `IPFILTER_LOG`. Эта команда может использоваться в двух различных режимах. В основном режиме, который используется по умолчанию, она используется без флага `-D`.

В режиме даемона создается непрерывный протокол, и возможен просмотр предыдущих событий. В этом режиме IPFILTER работает в FreeBSD. Поскольку в FreeBSD встроена функция ротации файлов протокола, лучше использовать man:syslogd[8], чем используемый по умолчанию вывод в обычный файл. В [.filename]#rc.conf# по умолчанию `ipmon_flags` имеет значение `-Ds`:

[.programlisting]
....
ipmon_flags="-Ds" # D = start as daemon
                  # s = log to syslog
                  # v = log tcp window, ack, seq
                  # n = map IP & port to names
....

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

Даже с включенным протоколированием, IPF не ведет протокол для каждого правила. Администратор межсетевого экран должен решить, по каким правилам набора нужно вести протокол и добавить ключевое слово log к этим правилам. Обычно протоколируются только правила, отбрасывающие пакеты.

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

=== Протоколирование IPMON

Для разделения собираемых данных syslogd использует свой собственный специальный метод. Он использует группировку по категории ("facility") и уровню ("level"). IPMON в режиме `-Ds` использует `local0` в качестве имени "категории". Для дальнейшего разделения протоколируемых данных, если такое необходимо, могут быть использованы следующие уровни:

[source,shell]
....
LOG_INFO - packets logged using the "log" keyword as the action rather than pass or block.
LOG_NOTICE - packets logged which are also passed
LOG_WARNING - packets logged which are also blocked
LOG_ERR - packets which have been logged and which can be considered short
....

Для указания IPFILTER протоколировать все данные в [.filename]#/var/log/ipfilter.log#, создайте этот файл заранее, выполнив следующую команду:

[source,shell]
....
# touch /var/log/ipfilter.log
....

Функционирование man:syslogd[8] управляется настройками в файле [.filename]#/etc/syslog.conf#. Файл [.filename]#syslog.conf# позволяет достаточно гибко настроить обработку системных сообщений, выдаваемых программами, такими как IPF.

Добавьте в [.filename]#/etc/syslog.conf# следующую запись:

[.programlisting]
....
local0.* /var/log/ipfilter.log
....

`local0.*` означает запись всех протоколируемых сообщений в указанный файл.

Для применения внесенных в [.filename]#/etc/syslog.conf# изменений вы можете перезагрузиться или заставить man:syslogd[8] перечитать [.filename]#/etc/syslog.conf#, выполнив команду `/etc/rc.d/syslogd reload`.

Не забудьте отредактировать [.filename]#/etc/newsyslog.conf# для ротации только что созданного лог файла.

=== Формат протоколируемых сообщений

Сообщения, генерируемые `ipmon`, состоят из полей данных, разделенных пробелами. Поля, общие для всех сообщений:

. Дата получения пакета.
. Время получения пакета. Формат времени HH:MM:SS.F для часов, минут, секунд и долей секунд (последнее поле может состоять из нескольких цифр).
. Имя интерфейса, через который прошел пакет, например [.filename]#dc0#.
. Группа и номер правила, например `@0:17`.

Эти сообщения могут быть просмотрены командой `ipfstat -in`.

. Действие: p для пропущенных, b для заблокированных, S для пакетов с неполным заголовком (short packet), n для пакетов, не соответствующих какому-либо правилу, L для соответствующих правилу протоколирования. Порядок следования по флагам: S, p, b, n, L. Знаки P или B в верхнем регистре означают, что пакет был протоколирован в соответствии с общими настройками, а не каким-то конкретным правилом.
. Адреса. Всего три поля: адрес и порт источника (разделенные запятой), ->, адрес и порт назначения. 209.53.17.22,80 -> 198.73.220.17,1722.
. `PR`, с последующим именем или номером протокола, например `PR tcp`.
. `len`, с последующей длиной заголовка и общей длиной пакета, например `len 20 40`.

Для TCP пакетов добавляется дополнительное поле, начинающееся с дефиса, за которым следуют буквы, соответствующие установленным флагам. На странице справочника man:ipf[5] находится список букв и флагов.

Для пакетов ICMP, в конце находятся два поля, одно всегда "ICMP", а второе содержит тип и подтип ICMP сообщения (message и sub-message), разделенные символом косой черты, например ICMP 3/3 для сообщения "port unreachable".

[[firewalls-ipf-rules-script]]
=== Создание набора правил с использованием символьной подстановки

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

Синтаксис скрипта совместим с man:sh[1], man:csh[1], и man:tcsh[1].

Символьная подстановка предваряется знаком доллара: `$`.

Для присвоения значения символьным переменным знак $ не используется.

Присваиваемое символической переменной значение должно быть заключено в двойные кавычки (`"`).

Начните файл правил примерно так:

[.programlisting]
....
############# Start of IPF rules script ########################

oif="dc0"            # name of the outbound interface
odns="192.0.2.11"    # ISP's DNS server IP address
myip="192.0.2.7"     # my static IP address from ISP
ks="keep state"
fks="flags S keep state"

# You can choose between building /etc/ipf.rules file
# from this script or running this script "as is".
#
# Uncomment only one line and comment out another.
#
# 1) This can be used for building /etc/ipf.rules:
#cat > /etc/ipf.rules << EOF
#
# 2) This can be used to run script "as is":
/sbin/ipf -Fa -f - << EOF

# Allow out access to my ISP's Domain name server.
pass out quick on $oif proto tcp from any to $odns port = 53 $fks
pass out quick on $oif proto udp from any to $odns port = 53 $ks

# Allow out non-secure standard www function
pass out quick on $oif proto tcp from $myip to any port = 80 $fks

# Allow out secure www function https over TLS SSL
pass out quick on $oif proto tcp from $myip to any port = 443 $fks
EOF
################## End of IPF rules script ########################
....

Это все, что требовалось сделать. В данном примере сами правила не важны; важно то, как используется символьная подстановка. Если вышеприведенный пример помещен в файл [.filename]#/etc/ipf.rules.script#, то набор правил можно перезагрузить, введя следующую команду:

[source,shell]
....
# sh /etc/ipf.rules.script
....

С использованием в правилах символьной подстановки связана одна проблема: IPF не понимает символьную подстановку и не может обработать такой скрипт непосредственно.

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

* Уберите комментарий перед строкой, начинающейся с `cat`, и закомментируйте строку, начинающуюся с `/sbin/ipf`. Поместите строку `ipfilter_enable="YES"` в файл [.filename]#/etc/rc.conf# как обычно, и запускайте скрипт после каждого его обновления для создания или обновления файла [.filename]#/etc/ipf.rules#.
* Отключите IPFILTER в стартовых скриптах системы, поместив строку `ipfilter_enable="NO"` (это значение по умолчанию) в файл [.filename]#/etc/rc.conf#.
+ 
Поместите скрипт, подобный нижеприведенному, в каталог [.filename]#/usr/local/etc/rc.d/#. У него должно быть однозначно говорящее о его назначении имя, например [.filename]#ipf.loadrules.sh#. Расширение [.filename]#.sh# обязательно.
+
[.programlisting]
....
#!/bin/sh
sh /etc/ipf.rules.script
....

+ 
Права, установленные на этот файл, должны разрешать чтение, запись и выполнение владельцу `root`.
+

[source,shell]
....
# chmod 700 /usr/local/etc/rc.d/ipf.loadrules.sh
....

Теперь, правила IPF будут загружаться при загрузке системы.

=== Наборы правил IPF

Набор правил ipf это группа правил, составленных для пропускания или блокирования пакетов на основе их содержимого. Двусторонний обмен пакетами между хостами составляет сессию. Межсетевой экран обрабатывает как входящие из Интернет пакеты, так и исходящие пакеты, которые сгенерированы самой системой в ответ на входящий трафик. Для каждой службы TCP/IP (например, telnet, www, mail, и т.п.) назначен протокол и номер привилегированного (прослушиваемого) порта. Пакеты, предназначенные для определенного сервиса, порождаются с некоторым исходящим адресом и портом из непривилегированного диапазона и направляются на определенный адрес и определенный порт назначения. Все упомянутые параметры (номера портов и адреса) могут использоваться как критерии выбора в правилах, пропускающих или блокирующих доступ к службам TCP/IP.

IPF был первоначально написан с использованием логики "последнее совпадающее правило побеждает" и только с правилами без сохранения состояния. Со временем в IPF был включен параметр "quick" и параметр сохранения состояния "keep state", что существенно улучшило логику обработки правил.

Инструкции, помещенные в эту главу, созданы с использованием параметров "quick" и "keep state". Это основа для создания набора правил включающего межсетевого экрана.

[WARNING]
====

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

[[firewalls-ipfw]]
== IPFW

IPFIREWALL (IPFW) - представляет собой межсетевой экран, написанный и поддерживаемый добровольными участниками проекта FreeBSD. Он использует stateless правила, т.е. правила без учета состояния, и наследование техники кодирования правил для получения того, что называется простой логикой с сохранением состояния (stateful).

Пример простейшего набора правил IPFW (находится в [.filename]#/etc/rc.firewall# и [.filename]#/etc/rc.firewall6#) в стандартной установке FreeBSD достаточно прост и не рассчитан на непосредственное использование без изменений. В нём не используется фильтрация с сохранением состояния, которая даёт преимущества во многих конфигурациях, поэтому он не может быть взят за основу для этого раздела.

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

IPFW состоит из семи компонентов, главный из которых - процессор правил фильтрации уровня ядра и интегрированный в него механизм учета пакетов, а также средства протоколирования пакетов, правило `divert`, посредством которых вызывается функция NAT и другие возможности специального назначения, средства для ограничения скорости (шейпинга) трафика (dummynet), средства перенаправления `fwd`, средства организации сетевого моста bridge и механизм ipstealth. IPFW поддерживает протоколы IPv4 и IPv6.

[[firewalls-ipfw-enable]]
=== Включение IPFW

IPFW включён в базовую установку FreeBSD в виде отдельного подгружаемого модуля. Система динамически загружает модуль ядра, когда в [.filename]#rc.conf# присутствует строка `firewall_enable="YES"`. Если использовать функциональность NAT не планируется, то в этом случае дополнительно компилировать IPFW в состав ядра FreeBSD не требуется.

После перезагрузки системы с `firewall_enable="YES"` в [.filename]#rc.conf# на экране в процессе загрузки отобразится выделенное белым сообщение:

[source,shell]
....
ipfw2 initialized, divert disabled, rule-based forwarding disabled, default to deny, logging disabled
....

Загружаемый модуль скомпилирован с возможностью протоколирования информации о трафике. Для включения протоколирования и установки уровня его детализации имеется переключатель, значение которого можно установить в конфигурационном файле [.filename]#/etc/sysctl.conf#. При добавлении следующих двух строк протоколирование будет включено при следующей загрузке системы:

[.programlisting]
....
net.inet.ip.fw.verbose=1
net.inet.ip.fw.verbose_limit=5
....

[[firewalls-ipfw-kernel]]
=== Параметры ядра

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

[.programlisting]
....
options    IPFIREWALL
....

Этот параметр включает IPFW в состав ядра.

[.programlisting]
....
options    IPFIREWALL_VERBOSE
....

Этот параметр включает протоколирование пакетов, которые проходят через IPFW по правилам с ключевым словом `log`.

[.programlisting]
....
options    IPFIREWALL_VERBOSE_LIMIT=5
....

Ограничение числа пакетов, прошедших через man:syslogd[8], отдельно для каждого правила. Этот параметр имеет смысл использовать в недружественной среде, когда необходимо отслеживать активность межсетевого экрана. Это закрывает возможность атак типа "отказ в обслуживании" через флуд сообщениями syslog.

[.programlisting]
....
options    IPFIREWALL_DEFAULT_TO_ACCEPT
....

Этот параметр включает для IPFW разрешающую политику по умолчанию. Это удобно на первых этапах настройки IPFW.

[.programlisting]
....
options    IPDIVERT
....

Включение функциональности NAT.

[NOTE]
====
Межсетевой экран будет блокировать все входящие и исходящие пакеты, если отсутствует параметр ядра `IPFIREWALL_DEFAULT_TO_ACCEPT` или правило, явно разрешающее эти соединения.
====

[[firewalls-ipfw-rc]]
=== Параметры [.filename]#/etc/rc.conf#

Включение межсетевого экрана:

[.programlisting]
....
firewall_enable="YES"
....

Для выбора одного из стандартных режимов работы межсетевого экрана, предоставляемых FreeBSD, выберите наиболее подходящий в файле [.filename]#/etc/rc.firewall# и разместите так, как указано ниже:

[.programlisting]
....
firewall_type="open"
....

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

* `open` - пропускать весь трафик.
* `client` - защищать только эту машину.
* `simple` - защищать всю сеть.
* `closed` - полностью запретить IP трафик, за исключением loopback интерфейса.
* `UNKNOWN` - отключить загрузку правил межсетевого экрана.
* [.filename]#filename# - абсолютный путь к файлу, содержащему правила межсетевого экрана.

Есть два варианта загрузки собственных правил в межсетевой экран ipfw. Первый способ - задать переменную `firewall_type` в виде абсолютного пути файла, содержащего _правила межсетевого экрана_ без каких-либо параметров командной строки для самого man:ipfw[8]. Ниже приведён простой пример набора правил, который блокирует весь входящий и исходящий трафик:

[.programlisting]
....
add deny in
add deny out
....

Второй способ - установить значение переменной `firewall_script` в виде абсолютного пути исполняемого скрипта, содержащего команды `ipfw`, которые будут выполнены во время загрузки операционной системы. Правильный формат правил исполняемого скрипта должен соответствовать формату файла, приведённому ниже:

[.programlisting]
....
#!/bin/sh

ipfw -q flush

ipfw add deny in
ipfw add deny out
....

[NOTE]
====
Если переменной `firewall_type` присвоено значение `client` или `simple`, то правила, расположенные по умолчанию в [.filename]#/etc/rc.firewall#, должны быть приведены в соответствие с конфигурацией данной машины. Также заметим, что для используемых в этой главе примеров в качестве значения переменной `firewall_script` используется [.filename]#/etc/ipfw.rules#.
====

Включение протоколирования:

[.programlisting]
....
firewall_logging="YES"
....

[WARNING]
====

Единственное, что делает параметр `firewall_logging`, - присвоение логической единицы (`1`) переменной sysctl `net.inet.ip.fw.verbose` (смотрите <<firewalls-ipfw-enable>>). В [.filename]#rc.conf# нет переменной для ограничения протоколирования, но это можно сделать через переменную sysctl вручную либо используя файл [.filename]#/etc/sysctl.conf#:

[.programlisting]
....
net.inet.ip.fw.verbose_limit=5
....

====

Если ваша машина выполняет роль шлюза, т.е. обеспечивает трансляцию сетевых адресов (NAT) с помощью man:natd[8], имеет смысл сразу перейти к чтению crossref:advanced-networking[network-natd,Даемон преобразования сетевых адресов (natd)] для уточнения информации относительно параметров [.filename]#/etc/rc.conf#.

[[firewalls-ipfw-cmd]]
=== Команда IPFW

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

Тем не менее, команду `ipfw` удобно использовать для отображения текущей конфигурации правил на экране консоли. Учетный модуль IPFW динамически создаёт счётчики для каждого правила, которые подсчитывают количество пакетов, соответствующих условиям срабатывания правила. В процессе тестирования отображение правила со своим счётчиком является одним из способов проверки, срабатывает ли правило при прохождении через него пакета или нет.

Вывод полного списка правил:

[source,shell]
....
# ipfw list
....

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

[source,shell]
....
# ipfw -t list
....

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

[source,shell]
....
# ipfw -a list
....

Вывод динамических правил вместе со статическими:

[source,shell]
....
# ipfw -d list
....

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

[source,shell]
....
# ipfw -d -e list
....

Обнуление счетчиков:

[source,shell]
....
# ipfw zero
....

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

[source,shell]
....
# ipfw zero NUM
....

[[firewalls-ipfw-rules]]
=== Набор правил IPFW

Набор правил (ruleset) представляет собой группу правил IPFW, которые разрешают или запрещают прохождение пакета через межсетевой экран на основании значений, содержащихся в пакете. Двунаправленный обмен пакетов между машинами является сессией. Набор правил межсетевого экрана анализирует как пакеты, приходящие из глобальной сети, так и ответные пакеты, исходящие из системы. Каждый TCP/IP сервис (такой как telnet, www, mail, и т.д.) принадлежит определенному протоколу и привилегированному (прослушиваемому) порту. Пакеты, предназначенные для конкретного сервиса, передаются с непривилегированного (с высоким значением) порта по адресу назначения на указанный порт сервиса. Все эти параметры (т.е. порты и адреса) могут быть использованы в качестве критериев фильтрации при создании правил, которые пропускают или блокируют сервисы.

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

[NOTE]
====
Поиск продолжается после правил `count`, `skipto` и `tee`.
====

Упомянутые здесь инструкции основаны на использовании правил, содержащих параметры с сохранением состояния `keep state`, `limit`, `in`, `out` и `via`. Это основной механизм для кодирования набора правил межсетевого экрана закрытого типа.

[WARNING]
====

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

[[firewalls-ipfw-rules-syntax]]
==== Синтаксис правил

Представленный здесь синтаксис правил был упрощен для создания стандартного набора правил межсетевого экрана закрытого типа. Для полного описания синтаксиса правил смотрите страницу Справочника man:ipfw[8].

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

Символ `#` используется для обозначения начала комментария и может быть расположен в конце строки с правилом или в начале строки над правилом. Пустые строки игнорируются.

_CMD RULE_NUMBER ACTION LOGGING SELECTION STATEFUL_

===== CMD

Каждое новое правило должно начинаться с префикса [parameter]#add# для добавления во внутреннюю таблицу.

===== RULE_NUMBER

Каждое правило обозначено номером в диапазоне 1..65535.

===== ACTION

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

[parameter]#allow | accept | pass | permit#

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

[parameter]#check-state#

Проверяет пакет на соответствие динамической таблице правил. Если совпадение найдено, выполняется действие, содержащееся в правиле, породившем данное динамическое правило, иначе выполняется переход к следующему правилу. Правило check-state не имеет критериев фильтрации. При отсутствии правила check-state в наборе правил проверка по динамической таблице происходит на первом правиле keep-state или limit.

[parameter]#deny | drop#

Оба слова означают отбрасывание пакетов, совпавших с правилом. Поиск прекращается.

===== Протоколирование

[parameter]#log# или [parameter]#logamount#

Когда пакет совпадает с правилом, содержащим ключевое слово `log`, информация об этом событии записывается в man:syslogd[8] с пометкой SECURITY. Запись в журнал происходит только в том случае, если число срабатываний для данного правила не превышает значения параметра `logamount`. Если значение `logamount` не объявлено, то ограничение берется из значения переменной sysctl `net.inet.ip.fw.verbose_limit`. В обоих случаях обнуление значения отменяет ограничение. По достижению установленного лимита запись в журнал может быть повторно включена путем сброса счетчика срабатываний или счетчика пакетов для этого правила; смотрите описание команды `ipfw reset log`.

[NOTE]
====
Протоколирование осуществляется после проверки на соответствие всем условиям в правиле и перед выполнением окончательного действия (accept, deny) над пакетом. Вы должны выбрать сами, какие действия правил вы хотите включить в журнал.
====

===== Условия отбора

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

[parameter]#udp | tcp | icmp#

Также могут быть использованы имена протоколов, описанные в [.filename]#/etc/protocols#. Указанное значение обозначает протокол для совпадения. Это является обязательным требованием.

[parameter]#from src to dst#

Ключевые слова `from` и `to` служат для фильтрации по IP адресам. Обязательно должны быть указаны и источник, и получатель. `any` - это специальное ключевое слово, которое соответствует любому IP адресу. `me` - это специальное ключевое слово, которое соответствует любому из IP адресов, сконфигурированных на интерфейсе вашей системы FreeBSD, и служит для указания компьютера, на котором работает межсетевой экран (т.е. этот компьютер), как показано на примерах `from me to any`, `from any to me`, `from 0.0.0.0/0 to any`, `from any to 0.0.0.0/0`, `from 0.0.0.0 to any`, `from any to 0.0.0.0` и `from me to 0.0.0.0`. IP адрес указывается в виде четырёх чисел, разделённых точками, или дополнительно с префиксом сети (нотация CIDR). Это является обязательным требованием. Для упрощения вычислений, связанных с IP адресами, используйте порт package:net-mgmt/ipcalc[]. Более подробную информацию можно посмотреть на странице программы: http://jodies.de/ipcalc[http://jodies.de/ipcalc].

[parameter]#port number#

Для протоколов, работающих с портами (такие как TCP и UDP), обязательным требованием является указание номера порта соответствующего сервиса. Вместо номера порта можно использовать имя сервиса (из [.filename]#/etc/services#).

[parameter]#in | out#

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

[parameter]#via IF#

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

[parameter]#setup#

Это обязательное ключевое слово определяет начало запроса сессии для TCP пакетов.

[parameter]#keep-state#

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

[parameter]#limit {src-addr | src-port | dst-addr | dst-port}#

Межсетевой экран разрешит только _N_ соединений с одинаковым набором параметров, указанных в правиле. Можно задавать один или несколько адресов и портов отправителя и получателя. В одном и том же правиле использование `limit` и `keep-state` не допускается. Параметр `limit` предоставляет такую же функцию с сохранением состояний, что и `keep-state`, плюс свои собственные.

==== Параметры для правил с сохранением состояния

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

Параметр `check-state` служит для указания места в наборе правил IPFW, в котором пакет будет передан на поиск соответствий динамическим правилам. В случае совпадения пакет пропускается, при этом создается новое динамическое правило для следующего пакета, принадлежащего данной двусторонней сессии. В противном случае пакет движется по обычным правилам, начиная со следующей позиции.

Динамические правила уязвимы к атаке SYN-пакетами, которые могут породить гигантское количество динамических правил. Для предотвращения такого рода атак во FreeBSD предусмотрен еще один параметр - `limit`. Этот параметр служит для ограничения количества одновременно установленных сессий путём проверки полей отправителя и получателя, в зависимости от параметра `limit`, с использованием IP адреса пакета для поиска открытых динамических правил, которые представляют собой счетчик количества совпадений для данного IP адреса и этого правила. Если это количество превышает значение, указанное в параметре `limit`, то такой пакет отбрасывается.

==== Протоколирование сообщений межсетевого экрана

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

Даже при включенной функции ведения журнала само по себе оно производиться не будет. Администратор межсетевого экрана определяет, для каких правил будет включена функция ведения журнала, и добавляет к этим правилам `log`. Обычно в журнал пишутся только запрещающие правила, такие как правила deny для входящего ICMP ping. Довольно часто конец списка добавляют дублирующее правило вида "ipfw default deny everything" с приставкой `log`. Это позволяет отслеживать все пакеты, не совпадающие ни с одним из правил в вашем наборе.

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

Параметр ядра `IPFIREWALL_VERBOSE_LIMIT=5` ограничивает число идущих подряд сообщений в системный регистратор man:syslogd[8], касающихся пакетов, совпавших с правилом. Когда этот параметр включен в ядро, число последовательно идущих сообщений для определенного правила обрезается указанным числом. От записи 200 идентичных сообщений особого прока нет. В данном случае для сработавшего правила в журнале syslogd будут зафиксированы 5 сообщений подряд, остальные идентичные сообщения будут подсчитаны и отправлены в syslogd как одно сообщение такого вида:

[.programlisting]
....
last message repeated 45 times
....

Путь к файлу, в который пишутся сообщения, задается в файле [.filename]#/etc/syslog.conf#. По умолчанию это файл [.filename]#/var/log/security#.

[[firewalls-ipfw-rules-script]]
==== Написание скрипта правил

Наиболее опытные пользователи IPFW создают скрипт, содержащий в себе правила, оформленные таким образом, что они могут быть исполнены как обыкновенный sh-скрипт. Основное преимущество такого подхода в том, что правила можно полностью заменить на новые без необходимости в перезагрузке системы для их активации. Это крайне удобно на этапе разработки и тестирования набора правил, т.к. перезагружать весь список правил можно сколь угодно часто. Помимо того, поскольку это скрипт, то здесь можно объявить некие часто используемые значения в виде переменной, и использовать её во множестве правил, как показано в примере ниже.

Синтаксис примера, приведенного ниже, совместим с тремя командными оболочками: man:sh[1], man:csh[1], man:tcsh[1]. Для использования значения ранее объявленной переменной имя переменной предваряется символом $. Во время присвоения имя переменной не имеет префикса $, присваиваемое значение должно быть заключено в "двойные кавычки".

Так выглядит файл с правилами, с которого вы можете начать:

[.programlisting]
....
############### начало примера скрипта с правилами ipfw #############
#
ipfw -q -f flush	# Сброс всех правил.
# Установки по умолчанию
oif="tun0"		# наш интерфейс
odns="192.0.2.11"	# IP DNS сервера провайдера
cmd="ipfw -q add "	# префикс для создания правил
ks="keep-state"		# просто лень вводить каждый раз
$cmd 00500 check-state
$cmd 00502 deny all from any to any frag
$cmd 00501 deny tcp from any to any established
$cmd 00600 allow tcp from any to any 80 out via $oif setup $ks
$cmd 00610 allow tcp from any to $odns 53 out via $oif setup $ks
$cmd 00611 allow udp from any to $odns 53 out via $oif $ks
################### конец примера скрипта с правилами ipfw ############
....

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

Если бы этот скрипт находился в файле [.filename]#/etc/ipfw.rules#, то правила можно было бы перезагрузить следующей командой.

[source,shell]
....
# sh /etc/ipfw.rules
....

Имя и расположение файла [.filename]#/etc/ipfw.rules# могут быть какими угодно.

Такой же результат можно получить, выполнив вручную следующие команды:

[source,shell]
....
# ipfw -q -f flush
# ipfw -q add check-state
# ipfw -q add deny all from any to any frag
# ipfw -q add deny tcp from any to any established
# ipfw -q add allow tcp from any to any 80 out via tun0 setup keep-state
# ipfw -q add allow tcp from any to 192.0.2.11 53 out via tun0 setup keep-state
# ipfw -q add 00611 allow udp from any to 192.0.2.11 53 out via tun0 keep-state
....

==== Набор правил с сохранением состояния

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

Все разновидности операционных систем UNIX(R), включая FreeBSD, используют интерфейс [.filename]#lo0# и IP адрес `127.0.0.1` для передачи данных внутри операционной системы. Правила межсетевого экрана должны содержать в своем составе правила, разрешающие беспрепятственное прохождение трафика по этому интерфейсу.

Интерфейс, подключенный к Интернет, является местом для размещения правил авторизации и контроля доступа исходящих и входящих соединений. Это может быть туннельный интерфейс PPP [.filename]#tun0# или сетевой адаптер, подключенный к DSL или кабельному модему.

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

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

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

Раздел, описывающий правила для исходящего трафика на внешнем интерфейсе, содержит только разрешающие правила `allow`, состоящие из значений фильтрации, которые однозначно определяют сервис, которому разрешен доступ в Интернет. Все правила включают в себя поля `proto`, `port`, `in/out`, `via` и `keep state`. Правила, содержащие `proto tcp`, имеют также параметр `setup`, который служит для определения начала сессии, которое в дальнейшем передается как условие срабатывания в динамическую таблицу.

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

Также следует убедиться в том, что ваш сервер не отвечает ни на какие другие формы непредусмотренного трафика. Некорректные пакеты должны быть просто отброшены. В результате атакующие не получат информацию о том, достиг ли его пакет вашего сервера. Чем меньше атакующие будут знать о вашей системе, тем более она защищена. Назначение нераспознанного номера порта можно посмотреть в файле [.filename]#/etc/services/# или по адресу http://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers[http://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers]. Рекомендуем ознакомиться с содержимым ссылки относительно номеров портов, используемых троянами: http://www.sans.org/security-resources/idfaq/oddports.php[http://www.sans.org/security-resources/idfaq/oddports.php].

==== Пример правил для межсетевого экрана закрытого типа.

Следующие правила, не включающие поддержку NAT, являются логически полным набором правил для межсетевого экрана закрытого типа. При использовании этого набора правил вы вполне можете быть уверены в безопасности вашей системы. Просто закомментируйте некоторые из правил `pass` для тех служб, которые вам не требуются. Чтобы избежать занесения в журнал нежелательных сообщений, добавьте правило `deny` в раздел, описывающий входящий трафик на интерфейсе. Замените название интерфейса [.filename]#dc0#, упоминающегося в правилах ниже, на название интерфейса (NIC), который соединяет вашу систему с глобальной сетью. Для PPP соединений это будет [.filename]#tun0#.

Примечание по использованию этих правил.

* Все запросы начала сессии с внешней сетью используют параметр `keep-state`.
* Все разрешенные сервисы внешней сети имеют параметр `limit` для защиты от флуда.
* Все правила используют параметры `in` или `out` для указания направления трафика.
* Все правила используют параметр `via` _имя-интерфейса_ для уточнения интерфейса, через который проходит пакет.

Следующие правила записываются в [.filename]#/etc/ipfw.rules#.

[.programlisting]
....
################ Начало файла с правилами IPFW ###############################
# Сброс всех правил перед началом работы скрипта.
ipfw -q -f flush

# Префикс для создания правил
cmd="ipfw -q add"
pif="dc0"		# название внешнего интерфейса,
			# принадлежащего глобальной сети

#################################################################
# Нет ограничений на внутреннем интерфейсе локальной сети
# Нет необходимости в этом, если у вас нет локальной сети.
# Замените xl0 на название интерфейса вашей локальной сети
#################################################################
#$cmd 00005 allow all from any to any via xl0

#################################################################
# Нет ограничений на интерфейсе Loopback
#################################################################
$cmd 00010 allow all from any to any via lo0

#################################################################
# Разрешить пакет, если он был ранее добавлен в "динамическую"
# таблицу при помощи выражения allow keep-state
#################################################################
$cmd 00015 check-state

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

# Разрешить исходящий трафик к DNS серверу провайдера
# x.x.x.x должен быть IP адресом DNS сервера вашего провайдера
# Продублируйте эти строки, если у вас больше одного DNS сервера
# Эти IP адреса можно взять из файла /etc/resolv.conf
$cmd 00110 allow tcp from any to x.x.x.x 53 out via $pif setup keep-state
$cmd 00111 allow udp from any to x.x.x.x 53 out via $pif keep-state

# Разрешить исходящий трафик к DHCP серверу провайдера для cable/DSL конфигураций.
# Это правило не нужно для .user ppp. соединений с глобальной сетью
# в этом случае вы можете удалить эти правила.
# Используйте это правило для записи необходимого нам IP адреса в лог-файл.
# Затем укажите IP адрес в закомментированном правиле и удалите первое правило.
$cmd 00120 allow log udp from any to any 67 out via $pif keep-state
#$cmd 00120 allow udp from any to x.x.x.x 67 out via $pif keep-state

# Разрешить исходящий трафик для незащищенного www соединения
$cmd 00200 allow tcp from any to any 80 out via $pif setup keep-state

# Разрешить исходящий трафик для защищенного www соединения
# https с поддержкой TLS и SSL
$cmd 00220 allow tcp from any to any 443 out via $pif setup keep-state

# Разрешить исходящий POP/SMTP
$cmd 00230 allow tcp from any to any 25 out via $pif setup keep-state
$cmd 00231 allow tcp from any to any 110 out via $pif setup keep-state

# Разрешить исходящий трафик для FreeBSD (make install & CVSUP)
# По сути назначаем пользователю root полные привилегии.
$cmd 00240 allow tcp from me to any out via $pif setup keep-state uid root

# Разрешаем исходящий icmp ping
$cmd 00250 allow icmp from any to any out via $pif keep-state

# Разрешаем исходящий трафик Time
$cmd 00260 allow tcp from any to any 37 out via $pif setup keep-state

# Разрешаем исходящий трафик nntp news
$cmd 00270 allow tcp from any to any 119 out via $pif setup keep-state

# Разрешаем исходящий защищённый трафик FTP, Telnet и SCP
# Эта функция использует SSH (secure shell)
$cmd 00280 allow tcp from any to any 22 out via $pif setup keep-state

# Разрешаем исходящий трафик whois
$cmd 00290 allow tcp from any to any 43 out via $pif setup keep-state

# Запрещаем и заносим в журнал остальной исходящий трафик.
# Обеспечивает политику межсетевого экрана закрытого типа
$cmd 00299 deny log all from any to any out via $pif

#################################################################
# Раздел правил для входящего трафика на внешнем интерфейсе
# Анализ пакетов, приходящих из глобальной сети,
# предназначенных для этого шлюза или локальной сети
########################################################################

# Запрещаем весь входящий трафик с немаршрутизируемых сетей
$cmd 00300 deny all from 192.168.0.0/16 to any in via $pif  #RFC 1918 private IP
$cmd 00301 deny all from 172.16.0.0/12 to any in via $pif     #RFC 1918 private IP
$cmd 00302 deny all from 10.0.0.0/8 to any in via $pif          #RFC 1918 private IP
$cmd 00303 deny all from 127.0.0.0/8 to any in via $pif        #loopback
$cmd 00304 deny all from 0.0.0.0/8 to any in via $pif            #loopback
$cmd 00305 deny all from 169.254.0.0/16 to any in via $pif   #DHCP auto-config
$cmd 00306 deny all from 192.0.2.0/24 to any in via $pif       #reserved for docs
$cmd 00307 deny all from 204.152.64.0/23 to any in via $pif  #Sun cluster interconnect
$cmd 00308 deny all from 224.0.0.0/3 to any in via $pif         #Class D & E multicast

# Запрещаем пинг извне
$cmd 00310 deny icmp from any to any in via $pif

# Запрещаем ident
$cmd 00315 deny tcp from any to any 113 in via $pif

# Запрещаем все Netbios службы. 137=name, 138=datagram, 139=session
# Netbios это MS/Windows сервис обмена.
# Блокируем MS/Windows hosts2 запросы сервера имен на порту 81
$cmd 00320 deny tcp from any to any 137 in via $pif
$cmd 00321 deny tcp from any to any 138 in via $pif
$cmd 00322 deny tcp from any to any 139 in via $pif
$cmd 00323 deny tcp from any to any 81 in via $pif

# Запрещаем любые опоздавшие пакеты
$cmd 00330 deny all from any to any frag in via $pif

# Запрещаем ACK пакеты, которые не соответствуют динамической таблице правил.
$cmd 00332 deny tcp from any to any established in via $pif

# Разрешаем входящий трафик с DHCP сервера провайдера.  Это правило
# должно содержать IP адрес DHCP сервера вашего провайдера, поскольку
# только ему разрешено отправлять пакеты данного типа.  Необходимо только
# для проводных и DSL соединений.  Для 'user ppp' соединений с глобальной
# сетью использовать это правило нет необходимости.  Это тот же IP адрес,
# выбранный и используемый вами в разделе правил для исходящего трафика.
#$cmd 00360 allow udp from any to x.x.x.x 67 in via $pif keep-state

# Разрешить входящий трафик для www, так как я использую сервер apache
$cmd 00400 allow tcp from any to me 80 in via $pif setup limit src-addr 2

# Разрешить входящий трафик безопасных FTP, Telnet и SCP из глобальной сети
$cmd 00410 allow tcp from any to me 22 in via $pif setup limit src-addr 2

# Разрешить входящий нешифрованный трафик Telnet из глобальной сети
# считается небезопасным, потому что ID и PW передаются через глобальную
# сеть в открытом виде.
# Удалите этот шаблон, если вы не используете telnet.
$cmd 00420 allow tcp from any to me 23 in via $pif setup limit src-addr 2

# Отбрасываем и заносим в журнал все входящие соединения снаружи
$cmd 00499 deny log all from any to any in via $pif

# Всё остальное запрещено по умолчанию
# Запрещаем и заносим в журнал все пакеты для дальнейшего анализа
$cmd 00999 deny log all from any to any
################ Конец файла правил IPFW ###############################
....

==== Пример правил с сохранением состояний и поддержкой NAT

Здесь перечислены некоторые дополнительные конфигурационные параметры, которые нужно включить, чтобы активировать функцию NAT в IPFW. В файл конфигурации ядра к остальным параметрам IPFIREWALL нужно добавить строку `option IPDIVERT`.

В дополнение к обычным параметрам IPFW в [.filename]#/etc/rc.conf# добавим следующее:

[.programlisting]
....
natd_enable="YES"		# Включить функцию NATD
natd_interface="rl0"		# Название внешнего сетевого интерфейса
natd_flags="-dynamic -m"	# -m = по возможности сохранить номера портов
....

Использование динамических правил с правилом `divert natd` (Network Address Translation) значительно затрудняет логику составления правил. Расположение `check-state` и `divert natd` в таблице правил влияет на поведение межсетевого экрана. Это уже не просто последовательный логический поток. При применении вышеозначенных параметров становится доступным новый тип действия `skipto`. При использовании `skipto` нумерация правил становится обязательной. В качестве аргумента `skipto` используется номер правила, к которому нужно перейти.

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

Обработка правил начинается с первого по счету и идет последовательно, по правилу за раз, до достижения конца файла, либо если проверяемый пакет соответствует критериям фильтрации; в последнем случае пакет покидает межсетевой экран. Для правил под номерами 100, 101, 450, 500 и 510 важен порядок их расположения. Эти правила управляют трансляцией исходящих и входящих пакетов, таким образом в таблицу keep-state заносятся только приватные IP адреса локальной сети. Обратите внимание, что все правила allow и deny указывают направление, по которому передается пакет (исходящее или входящее) и сетевой интерфейс. Также стоит отметить, что все запросы начала исходящей сессии передаются с использованием `skipto rule 500` для трансляции адресов.

Предположим, что пользователь локальной сети запрашивает страницу через браузер. Веб-страницы передаются по порту 80. Пакет входит в межсетевой экран. Этот пакет не попадает под правило 100, потому что в критериях фильтрации этого правила указан параметр `in`. Этот пакет не попадает под правило 101, потому что это первый пакет сессии и он еще не был занесен в динамическую таблицу keep-state. Достигнув, наконец, правила 125, пакет удовлетворяет всем критериям фильтрации. Этот пакет является выходящим из интерфейса, взаимодействующим с глобальной сетью. На данном этапе у пакета в качестве исходящего адреса всё еще указан приватный IP адрес локальной сети. По условию этого правила к пакету применяются два действия. Параметр `keep-state` создаст новую запись в динамической таблице keep-state, и выполнится действие, указанное в правиле. Указанное действие является частью информации, заносимой в динамическую таблицу. В данном случае это `skipto rule 500`. Правило 500 транслирует (NAT) адреса пакета и отпускает его наружу. Данное замечание очень важно. Этот пакет идет к цели, где генерируется ответный пакет и отправляется обратно. Этот новый пакет входит в начало списка правил. На этот раз пакет соответствует правилу 100 и его IP адрес назначения транслируется обратно на соответствующий IP адрес локальной сети. Затем он обрабатывается правилом `check-state`, и поскольку для него уже присутствует в динамической таблице правило, соответствующее данной сессии, пакет пропускается в локальную сеть. Дальше пакет приходит к отправившему его компьютеру локальной сети, и генерируется новый пакет, запрашивающий новую порцию данных с удаленного сервера. На этот раз пакет сразу проверяется правилом `check-state`, и в случае присутствия исходящей записи данного пакета выполняется действие `skipto 500`. Пакет переходит к правилу 500, транслируется и пропускается во внешнюю сеть.

Для входящего трафика все пакеты, являющиеся частью уже установленной сессии, автоматически разбираются правилом `check-state` и правильно расположенными правилами `divert natd`. Всё, что нам остается сделать, это запретить все плохие пакеты и разрешить прохождение внутрь сети пакетов только для разрешенных сервисов. Допустим, на сервере с межсетевым экраном запущен apache, и мы хотим разрешить людям из глобальной сети доступ на локальный веб-сайт. Новый входящий пакет, запрашивающий начало сессии, соответствует правилу 100, и его IP адрес транслируется как локальный IP системы с межсетевым экраном. Далее пакет проверяется на соответствие вредоносному трафику и в случае отсутствия соответствия попадает на правило 425. В случае соответствия данному правилу происходят две вещи. Пакет правил помещается в динамическую таблицу keep-state, но в этот раз любая новая сессия запросов, порожденных с этого IP, ограничена 2 одновременными соединениями. Это защищает от перегрузки сервис, работающей по указанному номеру порта. В качестве действия в правиле указан `allow`, следовательно пакет пропускается в локальную сеть. Пакет, сформированный в качестве ответа, попадает под `check-state` и распознается им как принадлежащий существующей сессии. Далее он передаётся на правило 500, где происходит обратная трансляция, после чего пакет пропускается на внешний интерфейс.

Пример файла правил #1:

[.programlisting]
....
#!/bin/sh
cmd="ipfw -q add"
skip="skipto 500"
pif=rl0
ks="keep-state"
good_tcpo="22,25,37,43,53,80,443,110,119"

ipfw -q -f flush

$cmd 002 allow all from any to any via xl0  # разрешаем трафик на локальном интерфейсе
$cmd 003 allow all from any to any via lo0  # разрешаем трафик на интерфейсе loopback

$cmd 100 divert natd ip from any to any in via $pif
$cmd 101 check-state

# Разрешенные исходящие пакеты
$cmd 120 $skip udp from any to xx.168.240.2 53 out via $pif $ks
$cmd 121 $skip udp from any to xx.168.240.5 53 out via $pif $ks
$cmd 125 $skip tcp from any to any $good_tcpo out via $pif setup $ks
$cmd 130 $skip icmp from any to any out via $pif $ks
$cmd 135 $skip udp from any to any 123 out via $pif $ks

# Запрещаем весь входящий трафик с немаршрутизируемых адресных пространств
$cmd 300 deny all from 192.168.0.0/16  to any in via $pif  #RFC 1918 для локальных IP
$cmd 301 deny all from 172.16.0.0/12   to any in via $pif  #RFC 1918 для локальных IP
$cmd 302 deny all from 10.0.0.0/8      to any in via $pif  #RFC 1918 для локальных IP
$cmd 303 deny all from 127.0.0.0/8     to any in via $pif  #loopback
$cmd 304 deny all from 0.0.0.0/8       to any in via $pif  #loopback
$cmd 305 deny all from 169.254.0.0/16  to any in via $pif  #DHCP авто-конфигурации
$cmd 306 deny all from 192.0.2.0/24    to any in via $pif  #Зарезервировано для документации
$cmd 307 deny all from 204.152.64.0/23 to any in via $pif  #Sun cluster
$cmd 308 deny all from 224.0.0.0/3     to any in via $pif  #Class D & E multicast

# Разрешаем входящие пакеты
$cmd 400 allow udp from xx.70.207.54 to any 68 in $ks
$cmd 420 allow tcp from any to me 80 in via $pif setup limit src-addr 1

$cmd 450 deny log ip from any to any

# Раздел skipto для правил с сохранением состояния для исходящих пакетов
$cmd 500 divert natd ip from any to any out via $pif
$cmd 510 allow ip from any to any

######################## Окончание файла правил ##################
....

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

Пример файла правил #2:

[.programlisting]
....
#!/bin/sh
################ Начало файла правил IPFW ###############################
# Сброс всех правил перед началом работы скрипта.
ipfw -q -f flush

# Задание стандартных переменных
cmd="ipfw -q add"
skip="skipto 800"
pif="rl0"		# название внешнего интерфейса,
			# принадлежащего глобальной сети

#################################################################
# Нет ограничений на внутреннем интерфейсе локальной сети
# Замените xl0 на название интерфейса вашей локальной сети
#################################################################
$cmd 005 allow all from any to any via xl0

#################################################################
# Нет ограничений на интерфейсе Loopback
#################################################################
$cmd 010 allow all from any to any via lo0

#################################################################
# Трансляция адреса, если пакет является входящим
#################################################################
$cmd 014 divert natd ip from any to any in via $pif

#################################################################
# Разрешить пакет, если он был ранее добавлен в динамическую
# таблицу при помощи выражения allow keep-state
#################################################################
$cmd 015 check-state

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

# Разрешить исходящий трафик к DNS серверу провайдера
# x.x.x.x должен быть IP адресом DNS сервера вашего провайдера
# Продублируйте эти строки, если у вас больше одного DNS сервер
# Эти IP адреса можно взять из файла /etc/resolv.conf
$cmd 020 $skip tcp from any to x.x.x.x 53 out via $pif setup keep-state

# Разрешить исходящий трафик к DHCP серверу провайдера для cable/DSL конфигураций.
$cmd 030 $skip udp from any to x.x.x.x 67 out via $pif keep-state

# Разрешить исходящий трафик для незащищенного www соединения
$cmd 040 $skip tcp from any to any 80 out via $pif setup keep-state

# Разрешить исходящий трафик для защищенного www соединения
# https с поддержкой TLS и SSL
$cmd 050 $skip tcp from any to any 443 out via $pif setup keep-state

# Разрешить исходящий POP/SMTP
$cmd 060 $skip tcp from any to any 25 out via $pif setup keep-state
$cmd 061 $skip tcp from any to any 110 out via $pif setup keep-state

# Разрешить исходящий трафик для FreeBSD (make install & CVSUP)
# По сути назначаем пользователю root полные привилегии.
$cmd 070 $skip tcp from me to any out via $pif setup keep-state uid root

# Разрешаем исходящий icmp ping
$cmd 080 $skip icmp from any to any out via $pif keep-state

# Разрешаем исходящий трафик Time
$cmd 090 $skip tcp from any to any 37 out via $pif setup keep-state

# Разрешаем исходящий трафик nntp news (т.е. news groups)
$cmd 100 $skip tcp from any to any 119 out via $pif setup keep-state

# Разрешаем исходящий защищённый трафик FTP, Telnet и SCP
# Эта функция использует SSH (secure shell)
$cmd 110 $skip tcp from any to any 22 out via $pif setup keep-state

# Разрешаем исходящий трафик whois
$cmd 120 $skip tcp from any to any 43 out via $pif setup keep-state

# Разрешаем исходящий трафик ntp
$cmd 130 $skip udp from any to any 123 out via $pif keep-state

#################################################################
# Раздел правил для входящего трафика на внешнем интерфейсе
# Анализ пакетов, приходящих из глобальной сети,
# предназначенных для этого шлюза или локальной сети
#################################################################

# Запрещаем весь входящий трафик с немаршрутизируемых сетей
$cmd 300 deny all from 192.168.0.0/16  to any in via $pif  #RFC 1918 private IP
$cmd 301 deny all from 172.16.0.0/12   to any in via $pif  #RFC 1918 private IP
$cmd 302 deny all from 10.0.0.0/8      to any in via $pif  #RFC 1918 private IP
$cmd 303 deny all from 127.0.0.0/8     to any in via $pif  #loopback
$cmd 304 deny all from 0.0.0.0/8       to any in via $pif  #loopback
$cmd 305 deny all from 169.254.0.0/16  to any in via $pif  #DHCP auto-config
$cmd 306 deny all from 192.0.2.0/24    to any in via $pif  #reserved for docs
$cmd 307 deny all from 204.152.64.0/23 to any in via $pif  #Sun cluster
$cmd 308 deny all from 224.0.0.0/3     to any in via $pif  #Class D & E multicast

# Запрещаем ident
$cmd 315 deny tcp from any to any 113 in via $pif

# Запрещаем все Netbios службы. 137=name, 138=datagram, 139=session
# Netbios это MS/Windows сервис обмена.
# Блокируем MS/Windows hosts2 запросы сервера имен на порту 81
$cmd 320 deny tcp from any to any 137 in via $pif
$cmd 321 deny tcp from any to any 138 in via $pif
$cmd 322 deny tcp from any to any 139 in via $pif
$cmd 323 deny tcp from any to any 81  in via $pif

# Запрещаем любые опоздавшие пакеты
$cmd 330 deny all from any to any frag in via $pif

# Запрещаем ACK пакеты, которые не соответствуют динамической таблице правил.
$cmd 332 deny tcp from any to any established in via $pif

# Разрешаем входящий трафик с DHCP сервера провайдера. Это правило
# должно содержать IP адрес DHCP сервера вашего провайдера, поскольку
# только ему разрешено отправлять пакеты данного типа. Необходимо только
# для проводных и DSL соединений. Для 'user ppp' соединений с глобальной
# сетью использовать это правило нет необходимости. Это тот же IP адрес,
# выбранный и используемый вами в разделе правил для исходящего трафика.
$cmd 360 allow udp from x.x.x.x to any 68 in via $pif keep-state

# Разрешить входящий трафик для www, т.к. я использую Apache сервер.
$cmd 370 allow tcp from any to me 80 in via $pif setup limit src-addr 2

# Разрешить входящий трафик безопасных FTP, Telnet и SCP из глобальной сети
$cmd 380 allow tcp from any to me 22 in via $pif setup limit src-addr 2

# Разрешить входящий нешифрованный трафик Telnet из глобальной сети
# считается небезопасным, потому что ID и PW передаются через глобальную
# сеть в открытом виде.
# Удалите этот шаблон, если вы не используете telnet.
$cmd 390 allow tcp from any to me 23 in via $pif setup limit src-addr 2

# Отбрасываем и заносим в журнал все неразрешенные входящие соединения из глобальной сети
$cmd 400 deny log all from any to any in via $pif

# Отбрасываем и заносим в журнал все неразрешенные исходящие соединения в глобальную сеть
$cmd 450 deny log all from any to any out via $pif

# Место для skipto в правилах с сохранением состояния для исходящих соединений
$cmd 800 divert natd ip from any to any out via $pif
$cmd 801 allow ip from any to any

# Всё остальное запрещено по умолчанию
# Запрещаем и заносим в журнал все пакеты для дальнейшего анализа
$cmd 999 deny log all from any to any
################ Окончание файла правил IPFW ###############################
....
