Настройка Firewall, NAT,ALTQ на PF

Опубликовано:

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

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

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