Packet Filter (PF) — фаервол разработанный для OpenBSD и позже портированный на FreeBSD и NetBSD. По сравнению с тем же ipfw, имеет более понятный для чтения и написания правил синтаксис, имеет встроенный NAT, очереди и другие вкусности. Примеры конфигов можно увитеть тут: /usr/share/examples/pf.
В ОС FreeBSD он поставляется в виде подгружаемых модулей ядра, добавим его поддержку:
[root@router /]# cat /etc/rc.conf | grep pf
pf_enable="YES"
pf_rules="/etc/pf.conf"
pf_flags=""
pflog_enable="YES"
pflog_logfile="/var/log/pflog"
pflog_flags=""
gateway_enable="YES"
Если FreeBSD используется в качестве маршрутизатора, следует разрешить проброс пакетов, добавить в файл /etc/sysctl.conf:
net.inet.ip.forwarding=1
net.inet6.ip6.forwarding=1
Сам конфиг у нас находиться в /etc/pf.conf и имеет организованную структуру:
1. Макросы: Определяемые пользователем переменные, которые могут содержать адреса IP, имена интерфейсов, и т.д.
2. Таблицы: Применяются для хранения списков IP адресов.
3. Опции: Параметры, влияющие на работу pf.
4. Параметры нормализации Scrub: Подготовка пакета к нормализации и дефрагментации.
5. Приоретизация и очереди ALTQ: Обеспечивает управление полосой пропускания и установку приоритетов пакета.
6. Трансляции: Контроль NAT и перенаправление пакетов.
7. Правила фильтрации: Осуществляют выборочную фильтрацию пакетов на интерфейсах.
Для ясности происходящего приведу пример включения PF в сеть:
[root@router /]# cat /etc/pf.conf
####МАКРОСЫ####
# Внешний виртуальный сетевой интерфейс созданный PPPoE.
ext_if="tun0"# WAN ISP
int_isp="vr1"# Сетевой интерфейс который смотрит в мою домашнюю сеть.
int_if="vr0"router="192.168.1.1"
LAN="192.168.1.0/24"# Разрешенные типы icmp сообщений
allowed_icmp_types="{ echoreq, unreach }"
# Открытые порты со стороны интернет
servises_ext = "{ 21 80 3389 4899 5900 }"
# Cписок немаршрутизируемых адресов, с которых к нам будут долбиться на внешний интерфейс
non_route_nets_inet="{ 127.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12, 10.0.0.0/8, 169.254.0.0/16, 192.0.2.0/24, 0.0.0.0/8, 240.0.0.0/4 }"
####ТАБЛИЦЫ####
# Те, кто ходит у меня через NAT.
table <it> persist { 192.168.1.5 }
# Всем с сети 192.168.2.0/24 кроме 192.168.2.200.
#table <clients> { 192.168.2.0/24, !192.168.2.200 }
####CONTROL PF####
# Тем, кто лезет туда куда не нужно вежливо сообщаем что нельзя
#set block-policy return
# Если Вас досят, есть смысл поставить вместо "return".
set block-policy drop
# Не проверяем на lo0
set skip on lo0
# Изменяем время для состояния установленного tcp соединения, которое по-умолчанию чересчур большое (24часа).
set timeout { frag 10, tcp.established 3600 }
# Собирать пакеты перед отправкой
scrub in all
#Очереди, полоса - 2мбит, режем исходящий трафик от сервера с стороны внешнего интерфейса tun0.
altq on $ext_if cbq bandwidth 1980Kb queue { qssh, qhttp, qdns, qack, qftp }
queue qhttp bandwidth 70% priority 6 cbq (default borrow)
queue qssh bandwidth 15% priority 5 cbq (borrow)
queue qdns bandwidth 5% priority 5 cbq (borrow)
queue qack bandwidth 5% priority 6 cbq (borrow)
queue qftp bandwidth 5% priority 2 cbq (red)
#### NAT ####
# Тем, кто в таблице <it> разрешаем ходить в интернет через NAT, кроме 25 порта.
nat on $ext_if inet from <it> to any port != smtp -> ($ext_if)
# Для примера, NAT всех разрешенных портов, кроме www
#nat on $ext_if from $int_if:network to any port { ntp, nntp, domain } -> $ext_if
nat on $ext_if inet from 192.168.1.100 to any port smtp -> ($ext_if) #DBSERV
#### PORTMAPING ####
# Указываем какие порты редиректить и куда.
rdr on $ext_if inet proto tcp from any to any port 3389 -> 192.168.1.10 port 3389 #RDP
rdr on $ext_if inet proto tcp from any to any port 4899 -> 192.168.1.11 port 4899 #RADMIN
rdr on $ext_if inet proto tcp from any to $ext_if port 5900 -> 192.168.1.12 port 5900 #VNC
#### ПРАВИЛА ФИЛЬТРАЦИИ ####
# Блокируем всяких нехороших людей стандартный антиспуфинг средствами pf.
antispoof log quick for { lo0, $int_if, $ext_if }
#### $ext_if ####
#Блокируем все входящие на внешнем интерфейсе (ext_if) tun0
block in on $ext_if
#Рубаем Мультикастовые рассылки (Данные, предназначенные для приемом группой машин. В отличие от unicast и broadcast)
block in on $ext_if from any to 240.0.0.0/4
#Блокируем приватные сети на внешний интерфейс
block drop in quick on $ext_if from $non_route_nets_inet to any
block drop out quick on $ext_if from any to $non_route_nets_inet
#Разрешаем пинги на внешний интерфейс
pass in on $ext_if inet proto icmp all icmp-type $allowed_icmp_types
#Разрешаем ssh на внешнем интерфейсе
pass in quick on $ext_if inet proto tcp from any to any port 2222 keep state
#Разрешаем открытые порты на внешнем интерфейсе
pass in on $ext_if inet proto { tcp,udp } from any to any port $servises_ext flags S/SA keep state
#IN ALTQ
pass in on $ext_if inet proto { tcp,udp } from any to $ext_if port 2222 queue ( qssh, qack )
pass in on $ext_if inet proto { tcp,udp } from any to $ext_if port 80 queue qhttp
pass in on $ext_if inet proto { tcp,udp } from any to $ext_if port 53 queue qdns
pass in on $ext_if inet proto { tcp,udp } from any to $ext_if port { 21 30000:35000 } queue qftp
#OUT ALTQ
pass out on $ext_if inet proto { tcp,udp } from $ext_if to $ext_if port 2222 queue ( qssh, qack )
pass out on $ext_if inet proto { tcp,udp } from $ext_if to $ext_if port 80 queue qhttp
pass out on $ext_if inet proto { tcp,udp } from $ext_if to $ext_if port 53 queue qdns
pass out on $ext_if inet proto { tcp,udp } from $ext_if to $ext_if port { 21 30000:35000 } queue qftp
#Разрешить все исходящие на внешнем интерфейсе
pass out on $ext_if keep state
#### $int_isp ####
# Разрешаем все на этом интерфейсе.
pass in quick on $int_isp all
pass out quick on $int_isp all
#### $int_if ####
# Наша локалка
# Блокируем все входящие на внутр. интерфейсе (int_if)
block in on $int_if all
#Разрешаем пинги на внутр. интерфейсе
pass in on $int_if inet proto icmp all icmp-type $allowed_icmp_types
#Разрешаем открытые порты на внутр. интерфейсе
pass in on $int_if inet proto { tcp,udp } from $LAN to $router port 21 flags S/SA keep state #ftp
pass in on $int_if inet proto { tcp,udp } from $LAN to $router port 30000:35000 flags S/SA keep state #ftp-pasive
pass in on $int_if inet proto { tcp,udp } from $LAN to $router port 25 flags S/SA keep state #smtp
pass in on $int_if inet proto { tcp,udp } from $LAN to $router port 53 flags S/SA keep state #domain
pass in on $int_if inet proto { tcp,udp } from $LAN to $router port 67 flags S/SA keep state #dhcps
pass in on $int_if inet proto { tcp,udp } from $LAN to $router port 80 flags S/SA keep state #http
pass in on $int_if inet proto { tcp,udp } from $LAN to $router port 110 flags S/SA keep state #pop3
pass in on $int_if inet proto { tcp,udp } from $LAN to $router port 123 flags S/SA keep state #synctime (ntp)
pass in on $int_if inet proto { tcp,udp } from $LAN to $router port 137:139 flags S/SA keep state #samba
pass in on $int_if inet proto { tcp,udp } from $LAN to $router port 143 flags S/SA keep state #imap
pass in on $int_if inet proto { tcp,udp } from $LAN to $router port 445 flags S/SA keep state #microsoft-ds
pass in on $int_if inet proto { tcp,udp } from $LAN to $router port 465 flags S/SA keep state #ssmtp
pass in on $int_if inet proto { tcp,udp } from $LAN to $router port 993 flags S/SA keep state #imaps
pass in on $int_if inet proto { tcp,udp } from $LAN to $router port 995 flags S/SA keep state #pop3s
pass in on $int_if inet proto { tcp,udp } from $LAN to $router port 2222 flags S/SA keep state #SSH
pass in on $int_if inet proto { tcp,udp } from $LAN to $router port 3128 flags S/SA keep state #proxy
pass in on $int_if inet proto { tcp,udp } from $LAN to $router port 5222:5223 flags S/SA keep state #jabber
pass in on $int_if inet proto { tcp,udp } from $LAN to $router port 8000 flags S/SA keep state #stream-radio
pass in on $int_if inet proto { tcp,udp } from $LAN to $router port 9090 flags S/SA keep state #jabber-www-adminka
#for NAT
pass in on $int_if inet proto { tcp,udp } from <it> to any flags S/SA keep state
#Разрешить все исходящие на внутр. интерфейсе
pass out on $int_if keep state
PF имеет некоторые ключи для работы:
Включить pf:
[root@router /]# pfctl -e
Выключить pf:
[root@router /]# pfctl -d
Загрузить pf.sh:
[root@router /]# pfctl -f /etc/pf.conf
Анализировать, но не загружать конфиг:
[root@router /]# pfctl -nf /etc/pf.conf
Загрузить только правила NAT:
[root@router /]# pfctl -Nf /etc/pf.conf
Загрузить только правила фильтрации:
[root@router /]# pfctl -Rf /etc/pf.conf
Просмотр:
Показать текущие правила NAT:
[root@router /]# pfctl -sn
Показать текущие правила фильтрации:
[root@router /]# pfctl -sr
Показать текущее состояние таблиц:
[root@router /]# pfctl -ss
Показать статистику правил и состояние счетчиков:
[root@router /]# pfctl -si
Показать все:
[root@router /]# pfctl -sa
Просмотр очередей ALTQ в реалтайме:
[root@router /]# pfctl -vvsq
Подсчет трафика с помощью pf на определенных интерфейсах:
[root@router /]# pfctl -sI -vv -i tun0
Подсчет трафика с помощью pf на всех интерфейсах:
[root@router /]# pfctl -sI -vv
Сброс всех правил PF, полный клир:
[root@router /]# pfctl -F all
Логирование трафика
Для просмотра логов, которые находятся в /var/log/pflog и не читабельны простым редактором используют tcpdump:
[root@router /]# tcpdump -n -e -ttt -r /var/log/pf.log
В реальном времени:
[root@router /]# tcpdump -n -e -ttt -i pflog0
Для просмотра пакетов, которые прошли через определенный порт, в данном случае smtp порт:
[root@router /]# tcpdump -n -e -ttt -r /var/log/pflog port 25
Можно ограничить показ пакетов комбинацией указанных адреса хоста и порта:
[root@router /]# tcpdump -n -e -ttt -r /var/log/pflog port 80 and host 192.168.1.10
Такой же способ применим при чтении информации из интерфейса pflog0:
[root@router /]# tcpdump -n -e -ttt -i pflog0 host 192.168.1.10
Ставим в крон и отправляем себе на почту например каждый день в 8.00:
#!/bin/sh
tcpdump -n -e -r /var/log/pflog | mail admin(at)adminunix.ru && cat /dev/null > /var/log/pflog
Теперь пробуем проанализировать ваш конфиг:
[root@router /]#pfctl -nf /etc/pf.conf
если ошибок нет, значит все в порядке и можна загружать его в PF:
[root@router /]#pfctl -f /etc/pf.conf
Для большей безопасности я пересобираю ядро с поддержкой PF:
# Package Filter
options ALTQ
options ALTQ_CBQ
options ALTQ_RED
options ALTQ_RIO
options ALTQ_HFSC
options ALTQ_PRIQ
options ALTQ_NOPCC
device pf
device pflog
device pfsync
Вот вроде и всё.