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

Linux

Это называется  Linux audit trails. Как это настроить и использовать — описано здесь

FreeBSD

К сожалению, нормального аналога нет, но зато энтузиасты написали что-то похоже. Так же рекомендую прочесть другую заметку

Если вы работает с pf и во время загрузки правил получаете такое сообщение:

No ALTQ support in kernel
 ALTQ related functions disabled

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

 

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. (Дополнительная информация http://www-2.cs.cmu.edu/~hzhang/HFSC/main.html)

options ALTQ_PRIQ

включает Priority Queuing (  PRIQ  ).  PRIQ  всегда пропускает трафик из более высокой очереди первым.

options ALTQ_NOPCC

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

options ALTQ_CDNR
options ALTQ_DEBUG

Тестовый стенд: FreeBSD 8.2 i386

Условия — ограничить download (1000 Кбит/с) upload (2000 Кбит/с) с возможность заимствовать свободный трафик из ширины 5000 Кбит/с

ВНИМАНИЕ !!!

Ограничить можно только исходящий (upload) трафик, так как входящий (download) — уже пришёл и ограничить его нельзя. Но есть хитрый способ (не всегда даёт желаемый результат, но лучше, чем ничего): входящий на внутренний интерфейс (download) будет исходящим для внешнего. Именно так и будут составляться правила.

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

Правила шейпера:

altq on $ext_if cbq bandwidth 5000Kb queue { IN_ext, OUT_ext }
        queue IN_ext bandwidth 1000Kb cbq(default borrow)
        queue OUT_ext bandwidth 2000Kb
altq on $int_if cbq bandwidth 5000Kb queue { IN_int, OUT_int }
        queue IN_int bandwidth 1000Kb cbq(default borrow)
        queue OUT_int bandwidth 2000Kb

Навешиваем шейпер:

pass out on ext_if from any to $int_if:network queue IN_ext no state
 pass out on int_if from $int_if:network to any queue OUT_int no state

Напомню, что в pf’e важен порядок правил:

  • 1) макросы
  • 2) таблицы
  • 3) опции
  • 4) параметры нормализации
  • 5) приоретизация и очереди ALTQ
  • 6) правила трансляции
  • 7) правила фильтра

Поэтому правила, начинающиеся с altq/queue будут идти выше правил трансляции, а правила pass — вместе с правилами фильтрации.

А теперь, что бы посмотреть состояние очередей, выполним :

# pfctl -sq
 queue root_em0 on em0 bandwidth 5Mb priority 0 cbq( wrr root ) {IN_ext, OUT_ext}
 queue IN_ext on em0 bandwidth 1Mb cbq( borrow default )
 queue OUT_ext on em0 bandwidth 2Mb
 queue root_em1 on em1 bandwidth 5Mb priority 0 cbq( wrr root ) {IN_int, OUT_int}
 queue IN_int on em1 bandwidth 1Mb cbq( borrow default )
 queue OUT_int on em1 bandwidth 2Mb

Примечание.

Будьте внимательны при использовании borrow+cbq, так как оно не всегда работает, так как вам этого хочется. Яркий пример — не заимствование пропускной способности от родителей. Если кратко — то использовать вместо cbq -> hfsc

Сама проблема  https://lists.freebsd.org/pipermail/freebsd-pf/2009-March/005058.html
Решение проблемы  https://lists.freebsd.org/pipermail/freebsd-pf/2009-March/005061.html

Примечание 2.

В пакетном фильтре (начиная с OpenBSD 5.5) pf реализована новая система управления очередями сетевых пакетов, которая пришла на смену системе приоритизации трафика и управления пропускной способности ALTQ. Поддержка ALTQ пока сохранена, но будет удалена в следующем выпуске. Изменено действие правила блокировки по умолчанию, в pf.conf теперь используется «block return«. Простейший пример нового синтаксиса расстановки приоритетов для разного вида трафика:

 queue std on em0 bandwidth 100M
 queue ssh parent std bandwidth 10M
 queue mail parent std bandwidth 10M, min 5M, max 25M
 queue http parent std bandwidth 80M default

Необходимо было настроит динамический шейпер для локальной сети. Выбор стал между ipfw+dummynet и pf+altq. В результате шейпер решили настроить на dummynet, а правила NAT и фильтрации на PF, так как PF+ALTQ не дает возможности создания очереди на виртуальных интерфейсах (bridge, ng*, tun* ).
Визуальную статистику по пользователям, будем смотреть с помощью mrtg. Вышло даже неплохо.
Установленная ОС:

[root@pdcserv ~]# uname -rv
FreeBSD 8.1-RELEASE #0

Первым делом пересоберем ядро с поддержкой дамминета и PF:

#PF
device pf
device pflog
device pfsync
options ALTQ
options ALTQ_CBQ
options ALTQ_RED
options ALTQ_RIO
options ALTQ_HFSC
options ALTQ_PRIQ
options ALTQ_NOPCC#IPFW
options IPFIREWALL
options DUMMYNET
options HZ=1000

Далее необходимо немного тюнинговать ядро:

[root@pdcserv /etc]# cat /etc/sysctl.conf
net.inet.ip.forwarding=1 #включаем форвардинг пакетов
net.inet.ip.fastforwarding=1 #эта опция действительно ускоряет форвардинг
net.inet.tcp.blackhole=2 #ядро убивает tcp пакеты, приходящие в систему на непрослушиваемые порты
net.inet.udp.blackhole=0 #как и выше, только не убивает ибо traceroute пакеты не покажут этот хоп
net.inet.icmp.drop_redirect=1 #не обращаем внимания на icmp redirect
net.inet.icmp.log_redirect=0 #и не логируем их
net.inet.ip.redirect=0 #не реагируем на icmp redirect
net.inet.ip.sourceroute=0 #отключение маршрутизации от источника
net.inet.ip.accept_sourceroute=0 #старый и бесполезный механизм
net.inet.icmp.bmcastecho=0 #защита от SMURF атак
net.inet.icmp.maskrepl=0 #не отдавать по icmp паску своей подсети
net.link.ether.inet.max_age=30 #переспрашиваем каждые 30 секунд mac адреса в своём arp пространстве
net.inet.tcp.drop_synfin=1 #небольшая защита
net.inet.tcp.syncookies=1 #от доса
kern.ipc.somaxconn=32768 #увеличиваем размер очереди для сокетов
kern.maxfiles=204800 #увеличиваем число открытых файловых дескрипторов
kern.maxfilesperproc=200000 #кол-во ф.д. на каждоый процесс  
kern.ipc.nmbclusters=524288 #увеличиваем число сетевых буферов
kern.ipc.maxsockbuf=2097152 #
kern.random.sys.harvest.ethernet=0 #не использовать трафик и прерывания    
kern.random.sys.harvest.interrupt=0 #как источник энтропии для random'a  
net.inet.ip.dummynet.io_fast=1 #заставляет dummynet работать побыстрее  
net.inet.ip.dummynet.hash_size=65535 #  
net.inet.ip.dummynet.pipe_slot_limit=2048 #
kern.ipc.shmmax=67108864 #макс. размер сегмента памяти
net.inet.ip.intr_queue_maxlen=8192 #размер очереди ip-пакетов
#net.inet.ip.fw.one_pass=0 # 0=пакеты, прошедшие пайпы не вылетают из фаервола, а дальше идут по нему
net.inet.ip.fw.verbose=1
net.inet.ip.fw.verbose_limit=5
net.inet.ip.dummynet.hash_size=1024
net.inet.ip.fw.dyn_buckets=1024

Перейдем к настройке IPFW (dummynet);

[root@pdcserv /etc]#cat /etc/ipfw.conf
#!/bin/sh

cmd="ipfw -q"
lan=rl0 # LAN
wan=ae0 # WAN
drate=2Mbit/s # download
urate=2Mbit/s # upload
n=10 #Количество пользователей (1:253)

$cmd flush # Очищаем правила
$cmd pipe flush # Очищаем пайпы
$cmd table all flush # Очищаем все таблицы

# download (wan->lan)
$cmd pipe 100 config bw $drate queue 100 noerror
$cmd queue 111 config pipe 100 weight 50 queue 100 mask dst-ip 0xffffffff noerror

# upload (lan->wan)
$cmd pipe 200 config bw $urate  queue 100 noerror
$cmd queue 211 config pipe 200 weight 50 queue 100 mask src-ip 0xffffffff noerror

#Создаем очереди по таблицам
$cmd add queue tablearg ip from table(10) to any out recv $lan xmit $wan
$cmd add queue tablearg ip from any to table(11) out recv $wan xmit $lan

#Генерация правил подсчета трафика по пользователях
i=2
k=`expr $i + $n`
while [ "$i" -lt "$k" ]
do
$cmd add count all from any to 10.10.10.$i/32
$cmd add count all from 10.10.10.$i/32 to any
i=`expr $i + 1`
done

# IPFIREWALL_DEFAULT_TO_ACCEPT
$cmd add allow all from any to any

### Заполняем таблицы: ip номер_пайпы ###
# user_1
#$cmd table 10 add 10.10.10.2/32 211
#$cmd table 11 add 10.10.10.2/32 111

# user_2
#$cmd table 10 add 10.10.10.3/32 211
#$cmd table 11 add 10.10.10.3/32 111

# user_3
#$cmd table 10 add 10.10.10.4/32 211
#$cmd table 11 add 10.10.10.4/32 111
#user_all
$cmd table 10 add 10.10.10.0/24 211
$cmd table 11 add 10.10.10.0/24 111

На PF настраиваем только NAT:

[root@pdcserv /etc]#cat /etc/pf.conf
####МАКРОСЫ####
# WAN ISP
ext_if="ae0"

# LAN
int_if="rl0"

LAN="10.10.10.0/24"
#### NAT ####
# Разрешаем ходить в интернет через NAT
nat on $ext_if inet from $LAN to !$LAN -> ($ext_if)

Для автозапуска добавим строчки в /etc/rc.conf:

[root@pdcserv /etc]#cat >>  /etc/rc.conf
#pf  
pf_enable="YES"
pf_rules="/etc/pf.conf"
pf_flags=""
pflog_logfile="/var/log/pf.log"
pflog_flags=""#ipfw
firewall_enable="YES"
firewall_script="/etc/ipfw.conf"

Для визуальной статистики отдельно по каждому пользователю, необходимо добавить в конфиг MRTG блоки такого содержания:

#Общий блок
HtmlDir: /usr/local/www/mrtg
ImageDir: /usr/local/www/mrtg/img
LogDir: /usr/local/www/mrtg
Language: russian
Options[^]: growright, unknaszero, nobanner, transparent, noinfo, nopercent, integer
Background[_]: #B0C4DE
XSize[_]: 400
YSize[_]: 100# ipfw user_2
Target[user_2]: `ipfw show 300 | awk '{ print $3 }' && ipfw show 400 | awk '{ print $3 }'`
Title[user_2]: user_2
Pagetop[user_2]: <H1>user 192.168.100.2</H1>
Options[user_2]: bits
MaxBytes[user_2]:1250000

Вывод сгенерированных правил для 2-х пользователей:

[root@pdcserv ~]# ipfw show 
00100   0     0 queue tablearg ip from table(10) to any out recv rl0 xmit ae0
00200   0     0 queue tablearg ip from any to table(11) out recv ae0 xmit rl0
00300   0     0 count ip from any to 10.10.10.2
00400   0     0 count ip from 10.10.10.2 to any
00500   0     0 count ip from any to 10.10.10.3
00600   0     0 count ip from 10.10.10.3 to any
00700 129 48429 allow ip from any to any
65535   0     0 deny ip from any to any
[root@pdcserv ~]#

Просмотр текущих динамических очередей:

[root@pdcserv ~]# ipfw queue show
q00211 100 sl. 0 flows (1024 buckets) sched 200 weight 50 lmax 0 pri 0 droptail
mask:  0x00 0xffffffff/0x0000 -> 0x00000000/0x0000
BKT Prot ___Source IP/port____ ____Dest. IP/port____ Tot_pkt/bytes Pkt/Byte Drp
q00111 100 sl. 0 flows (1024 buckets) sched 100 weight 50 lmax 0 pri 0 droptail
mask:  0x00 0x00000000/0x0000 -> 0xffffffff/0x0000
BKT Prot ___Source IP/port____ ____Dest. IP/port____ Tot_pkt/bytes Pkt/Byte Drp
[root@pdcserv ~]#

Вот дошли руки и до корпоративного сервера — [urlspan]Exim[/urlspan]. Посмотрев статистику с помощью встроенного парсера логов(eximstats), решил что  блокировка спамеров  будет  проводиться  по IP.
Напишем скрипт, который будет запускать eximstats с необходимы опциями, парсить html-лог и складывать в файл «/etc/pf-mail-spammers» нежелательные IP, которые в качестве таблицы будут подгружаться в PF:

[root@router /]#cat eximstats.sh
/usr/local/sbin/eximstats -nt -nr -include_original_destination -chartdir/usr/local/www/eximstats/ -html=/usr/local/www/eximstats/ eximstats.html /var/log/exim/main
sleep 5
/usr/local/bin/php /eximstats.php
sleep 5
pfctl -f/etc/pf.sh

Парсер:

[root@router /]# cat eximstats.php 
<?php
$content=file_get_contents ('http://<ваш домен>/eximstats/#Rejected');
$pos = strpos ($content,'<h2>Top 50 rejected ips by message count</h2>');
$content = substr ($content, $pos);
$pos = strpos ($content, '<hr>');
$content = substr ($content, 0, $pos);
preg_match_all ('/d*.d*.d*.d*/', $content, $output);
foreach ($output as $index => $val)
{
foreach ($val as $val2)
{
if ((substr ($val2, 0, 3)!='127') and (substr ($val2, 0, 7)!='192.168'))
{
$mass[]=$val2;
}
}
}
$str = implode («n», $mass);
$file = fopen («/etc/pf-mail-spammers»,"w+");
fputs ( $file, $str);
fclose ($file);
echo ('ok')
?>

Добавим таблицу и блокирующее правило в /etc/pf.conf:

#Спамеры живут тут.
table <mailspam> persist file "/etc/pf-mail-spammers"
block in log quick from <mailspam>

Для просмотра лога eximstats, создадим каталог для местонахождения лога и добавим директорию в Apache:

[root@router /# mkdir /usr/local/www/eximstats
<Directory /usr/local/www/eximstats>
DirectoryIndex eximstats.html
AllowOverride None
Order deny,allow
Allow from <IP>
</Directory>

и вежливо перезапустим его:

[root@router /usr/local/etc/rc.d]# apachectl graceful
/usr/local/sbin/apachectl graceful: httpd gracefully restarted
[root@router /usr/local/etc/rc.d]# 

Теперь можно смотреть статистику по Exim в браузере:

http://<ваш домен>/eximstats/

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

[root@router /etc]# cat /etc/crontab | grep eximstats
#eximstats
58 23*** root /eximstats.sh

MRTG (Multi Router Traffic Grapher) — это свободное програмное обеспечение,  для визуального мониторинга по SNMP-протоколу. Но в данном примере я буду его использовать для визуализации текущей загрузки интернет канала провайдера.
Continue Reading

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 в сеть:

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

Вот вроде и всё.