Packet Filter (PF) на мой взгляд — уникальный файрвол, который можно настроить под самые фантастические задачи. Пробить его практически невозможно. Помимо основных задач он еще нормализует трафик TCP и отрубает неполноценные пакеты. Packet Filter (PF) — фаервол разработанный для OpenBSD и позже портированный на FreeBSD и NetBSD. По сравнению с тем же ipfw, имеет более понятный для чтения и написания правил синтаксис, имеет встроенный NAT, очереди и другие вкусности. Примеры конфигов можно увидеть тут: /usr/share/examples/pf. В ОС FreeBSD он поставляется в виде подгружаемых модулей ядра, добавим его поддержку:
В файл /etc/rc.conf добавим следующее
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# включить 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:
|
1 2 |
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 в сеть:
посмотрим конфигурационный файл
|
1 |
[root@router /]# cat /etc/pf.conf |
Во всех свежих версиях FreeBSD он уже присутствует в качестве загружаемого модуля. Но я включил его в ядро явно, нужно пересобрать ядро (это необязательно) :
(не бойтесь, что он такой большой. Для самых простых задач достаточно прописать строк десять )))
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
####МАКРОСЫ#### # Внешний виртуальный сетевой интерфейс созданный 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 имеет некоторые ключи для работы:
|
1 2 |
pfctl -e # включить (конфиг файл не считывается, его нужно подгружать отдельно) pfctl -d # наоборот, выключить |
Загрузить pf.sh:
|
1 |
[root@router /]# pfctl -f /etc/pf.conf |
Анализировать, но не загружать конфиг:
|
1 |
[root@router /]# pfctl -nf /etc/pf.conf |
Загрузить только правила NAT:
|
1 |
[root@router /]# pfctl -Nf /etc/pf.conf |
Загрузить только правила фильтрации:
|
1 |
[root@router /]# pfctl -Rf /etc/pf.conf |
Просмотр:
Показать текущие правила NAT:
|
1 |
[root@router /]# pfctl -sn |
Показать текущие правила фильтрации:
|
1 |
[root@router /]# pfctl -sr |
Показать текущее состояние таблиц:
|
1 |
[root@router /]# pfctl -ss |
Показать статистику правил и состояние счетчиков:
|
1 |
[root@router /]# pfctl -si |
Показать все:
|
1 |
[root@router /]# pfctl -sa |
Просмотр очередей ALTQ в реалтайме:
|
1 |
[root@router /]# pfctl -vvsq |
Подсчет трафика с помощью pf на определенных интерфейсах:
|
1 |
[root@router /]# pfctl -sI -vv -i tun0 |
Подсчет трафика с помощью pf на всех интерфейсах:
|
1 |
[root@router /]# pfctl -sI -vv |
Сброс всех правил PF, полный клир:
|
1 |
[root@router /]# pfctl -F all |
Для большей безопасности и резкого увеличения производительности пересобираю ядро с поддержкой PF (вообще-то это очень полезно, комментируете ненужные опции, пересобираете и ядро становится в два три раза меньше), в файл конфигурации ядра добавляем следующее:
|
1 2 3 4 5 6 7 8 9 10 11 |
# 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 |
Это пример с максимальным количеством настроек
СОВЕТ
Этот набор правил, вероятно, разрешает покидать сеть большему количеству трафика, чем требуется. Одна из таких конфигураций может генерировать этот макрос:
1 client_out = "{ ftp-data, ftp, ssh, domain, pop3, auth, nntp, http, https, cvspserver, 1528, 5999, 8000, 8080 }"Используйте приведенный выше макрос в основном правиле прохождения:
1 pass inet proto tcp from $localnet to any port $client_out flags S/SA keep stateМожет потребоваться еще несколько правил доступа. Следующий набор правил обеспечивает доступ по SSH во внешнем интерфейсе:
1 pass in inet proto tcp to $ext_if port sshСледующее определение и правило макроса позволяет внутренним клиентам использовать DNS и NTP:
1 udp_services = "{ domain, ntp }" pass q
Как управлять службой PF?
Чтобы запустить брандмауэр PF, вы можете выполнить следующую команду:
|
1 |
service pf start |
Чтобы остановить брандмауэр PF, вы можете выполнить следующую команду:
|
1 |
service pf stop |
Чтобы проверить PF на наличие синтаксической ошибки, вы можете выполнить следующую команду:
|
1 |
service pf check |
Чтобы перезапустить брандмауэр PF, вы можете выполнить следующую команду:
|
1 |
service pf restart |
Чтобы просмотреть состояние PF, вы можете выполнить следующую команду:
|
1 |
service pf status |
Чтобы запустить / остановить / перезапустить службу pflog, вы можете ввести следующие команды:
|
1 2 3 |
service pflog start service pflog stop service pflog restart |
…
