28.6. IPFW

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

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

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

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

28.6.1. Включение IPFW

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

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

ipfw2 initialized, divert disabled, rule-based forwarding disabled, default to deny, logging disabled

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

net.inet.ip.fw.verbose=1
net.inet.ip.fw.verbose_limit=5

28.6.2. Параметры ядра

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

options    IPFIREWALL

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

options    IPFIREWALL_VERBOSE

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

options    IPFIREWALL_VERBOSE_LIMIT=5

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

options    IPFIREWALL_DEFAULT_TO_ACCEPT

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

options    IPDIVERT

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

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

28.6.3. Параметры /etc/rc.conf

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

firewall_enable="YES"

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

firewall_type="open"

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

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

add deny in
add deny out

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

#!/bin/sh

ipfw -q flush

ipfw add deny in
ipfw add deny out

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

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

firewall_logging="YES"

Внимание: Единственное, что делает параметр firewall_logging, — присвоение логической единицы (1) переменной sysctl net.inet.ip.fw.verbose (смотрите Разд. 28.6.1). В rc.conf нет переменной для ограничения протоколирования, но это можно сделать через переменную sysctl вручную либо используя файл /etc/sysctl.conf:

net.inet.ip.fw.verbose_limit=5

Если ваша машина выполняет роль шлюза, т.е. обеспечивает трансляцию сетевых адресов (NAT) с помощью natd(8), имеет смысл сразу перейти к чтению Разд. 29.8 для уточнения информации относительно параметров /etc/rc.conf.

28.6.4. Команда IPFW

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

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

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

# ipfw list

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

# ipfw -t list

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

# ipfw -a list

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

# ipfw -d list

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

# ipfw -d -e list

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

# ipfw zero

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

# ipfw zero NUM

28.6.5. Набор правил IPFW

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

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

Замечание: Поиск продолжается после правил count, skipto и tee.

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

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

28.6.5.1. Синтаксис правил

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

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

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

CMD RULE_NUMBER ACTION LOGGING SELECTION STATEFUL

28.6.5.1.1. CMD

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

28.6.5.1.2. RULE_NUMBER

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

28.6.5.1.3. ACTION

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

allow | accept | pass | permit

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

check-state

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

deny | drop

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

28.6.5.1.4. Протоколирование

log или logamount

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

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

28.6.5.1.5. Условия отбора

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

udp | tcp | icmp

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

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 адресами, используйте порт net-mgmt/ipcalc. Более подробную информацию можно посмотреть на странице программы: http://jodies.de/ipcalc.

port number

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

in | out

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

via IF

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

setup

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

keep-state

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

limit {src-addr | src-port | dst-addr | dst-port}

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

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

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

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

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

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

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

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

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

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

last message repeated 45 times

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

28.6.5.4. Написание скрипта правил

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

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

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

############### начало примера скрипта с правилами 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 ############

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

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

# sh /etc/ipfw.rules

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

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

# 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

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

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

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

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

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

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

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

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

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

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

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

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

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

  • Все запросы начала сессии с внешней сетью используют параметр keep-state.

  • Все разрешенные сервисы внешней сети имеют параметр limit для защиты от флуда.

  • Все правила используют параметры in или out для указания направления трафика.

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

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

################ Начало файла с правилами 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 ###############################

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

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

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

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:

#!/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:

#!/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 ###############################

Этот, и другие документы, могут быть скачаны с ftp://ftp.FreeBSD.org/pub/FreeBSD/doc/.

По вопросам, связанным с FreeBSD, прочитайте документацию прежде чем писать в <questions@FreeBSD.org>.
По вопросам, связанным с этой документацией, пишите <doc@FreeBSD.org>.
По вопросам, связанным с русским переводом документации, пишите в рассылку <frdp@FreeBSD.org.ua>.
Информация по подписке на эту рассылку находится на сайте проекта перевода.