Мы — долго запрягаем, быстро ездим, и сильно тормозим.
www.lissyara.su —> статьи —> FreeBSD —> настройка —> PBR & PF

Настройка Policy Based Routing с помощью pf

Автор: fr33man.


Возникла необходимость настроить роутер, для маршрутизации пакетов между сетями. Так как на cisco начальство раскошеливаться не захотело(это намек =)), пришлось
ставить на компутер ОС, понятное дело, что я поставил чертенка, и настраивать должным образом файрвол. Выбирать firewall долго не пришлось,
вспомнив, как я мучился с ipfw и natd я тут же остановил свой выбор на packet filter(pf).
pf во FreeBSD, как и ipfw нужно подключать отдельно. Во FreeBSD версии < 5.x pf нужно было ставить из портов(/usr/ports/security/pf), но начиная
с 5-ой ветки начать работу с pf можно либо перекомпилировав ядро, либо подгрузив модуль pf.ko. Я пошел по первому пути, поэтому для начала давайте
соберем собственное ядрышко, добавив туда следующие опции:

device          pf
device          pflog
device          pfsync
options         ALTQ

После этого можно компилировать ядро и устанавливать его:


shield@/usr/src/sys/i386/conf> config kernel-pf
Kernel build directory is ../compile/kernel-pf
Don't forget to do ``make cleandepend; make depend''
shield@/usr/src/sys/i386/conf> cd ../compile/kernel-pf
shield@/usr/src/sys/i386/compile/kernel-pf> make cleandepend && \
? make depend && make && make install && reboot

После перезагрузки у вас в системе будет работающий firewall — pf. Теперь можно переходить непосредственно к настройке firewall'а.
Хотя нет, я погорячился... Сначала нужно... нет, просто НЕОБХОДИМО нарисовать схемку сети и продумать, какие пакеты будут ходить, кому
и куда можно. Короче просто продумать основные моменты. После этого можно приступать к написанию конфигурационного файла файрвола.
Конфиг pf находится по адресу: /etc/pf.conf. Его и будем мучать. Перед тем, как я опубликую свой конфигурационный файл, я хочу рассказать Вам о
структуре моей сети. Это необходимо, для понимания правил файрвола. Итак, все нижеописанное, Вы можете увидеть на данной схемке.
Роутер, на котором мы буде настраивать pf именуется shield, у него имеется 6 сетевых интерфейсов: 5 физических и один — VPN:


shield@/> ifconfig -a
dc0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
        options=8<VLAN_MTU>
        inet 192.168.98.2 netmask 0xffffff00 broadcast 192.168.98.255
        ether 00:05:1c:1e:6f:9e
        media: Ethernet autoselect (100baseTX <full-duplex>)
        status: active
dc1: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
        options=8<VLAN_MTU>
        inet 172.16.0.30 netmask 0xffffff00 broadcast 172.16.0.255
        ether 00:80:ad:0b:c7:9c
        media: Ethernet autoselect (100baseTX <full-duplex>)
        status: active
dc2: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
        options=8<VLAN_MTU>
        inet 192.168.3.2 netmask 0xffffff00 broadcast 192.168.3.255
        ether 00:05:1c:1e:5a:a0
        media: Ethernet autoselect (100baseTX <full-duplex>)
        status: active
fxp0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
        options=8<VLAN_MTU>
        inet 192.168.1.254 netmask 0xffffff00 broadcast 192.168.1.255
        ether 00:00:4b:51:07:84
        media: Ethernet autoselect (100baseTX <full-duplex>)
        status: active
fxp1: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
        options=b<RXCSUM,TXCSUM,VLAN_MTU>
        inet 10.10.20.1 netmask 0xffffff00 broadcast 10.10.20.255
        ether 00:02:b3:e8:21:ee
        media: Ethernet autoselect (100baseTX <full-duplex>)
        status: active
pfsync0: flags=0<> mtu 2020
pflog0: flags=100<PROMISC> mtu 33208
lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 16384
        inet 127.0.0.1 netmask 0xff000000
ng0: flags=88d1<UP,POINTOPOINT,RUNNING,NOARP,SIMPLEX,MULTICAST> mtu 1440
        inet 1.1.1.1 --> 172.17.0.1 netmask 0xffffffff
shield@/>

Из этих интерфейсов, два провайдера(dc0 и dc1), две локальных сети(dc2 и fxp0), DMZ(fxp1) и VPN(ng0), который соединяется с VPN-сервером в сети
172.16.0.0/24(dc1).
Маршрутом по умолчанию является 192.168.98.1(dc0). Почему он? Да потому что он более дешевый. ))) Тем более он будет больше всего загружен, так
как внешний интерфейс(ng0) будет использоваться только для входящих соединений на web-server, ftp, ssh, radmin и тд., и для исходящих
соединений по ssh, radmin, icq.
В принципе про сеть все что хотел, сказал. Осталось только составить pf.conf:


## Описываем переменные, содержащие имена интерфейсов

int_if="fxp0"
ext_if="ng0"
isp_if="dc0"
prov_if="dc1"
iikt_if="dc2"
dmz_if="fxp1"

## ip-адреса хостов, которые нам понадобятся

web_server="10.10.20.2"
ext_gateway="172.17.0.1"
mail="192.168.1.245"
proxy="192.168.3.2"
pinguin="192.168.3.3"
spider="192.168.1.250"
veterok="192.168.1.197"
backup="192.168.1.249"

## табличка с хостами, которым разрешен доступ в обход прокси. ))
table <servers> const { $spider, $mail, $backup }

## отбрасывать пакеты будем тихо, чтобы никто не догадался.. ))
set block-policy drop
## Игнорируем петлевой интерфейс
set skip on lo0

## нормализуем входящий трафик
scrub in all fragment reassemble
## нормализуем исходящтй трафик
## max-mss необходим из-за низкого mtu на внешнем канале
scrub out all random-id max-mss 1440

## пакеты, пришедшие на внешний интерфейс на порт 80, 221,
## 768, 799 или 20000 отправляем внутрь сети и метим их
rdr on $ext_if inet proto tcp to $ext_if port www tag WEB_SERVER -> \
    $web_server port www
rdr on $ext_if inet proto tcp to $ext_if port 221 tag FTP_SERVER -> \
    $web_server port ftp
rdr on $ext_if inet proto tcp to $ext_if port 768 tag SSH_SERVER -> \
    $spider port ssh
rdr on $ext_if inet proto tcp to $ext_if port 799 tag VETEROK -> \
    $veterok port 4899
rdr on $ext_if inet proto tcp to $ext_if port 20000 tag PINGUIN -> \
    $pinguin port 2004
## Отдаем пакеты идущие к ftp серверам нашей проксе
rdr pass on $int_if inet proto tcp from $int_if:network to !$web_server \
 port ftp -> 127.0.0.1 port 8021

## натим все пакеты на внешнем(ng0) интерфейсе, которые помечены
nat on $ext_if inet proto tcp tagged WEB_SERVER -> ($ext_if)
nat on $ext_if inet proto tcp tagged FTP_SERVER -> ($ext_if)
nat on $ext_if inet proto tcp tagged SSH_SERVER -> ($ext_if)
nat on $ext_if inet proto tcp tagged VETEROK -> ($ext_if)
nat on $ext_if inet proto tcp tagged PINGUIN -> ($ext_if)
nat on $ext_if inet proto tcp tagged RADMIN -> ($ext_if)
nat on $ext_if inet proto tcp tagged SSH -> ($ext_if)
nat on $ext_if inet proto tcp tagged ICQ -> ($ext_if)
## Наш ftp сервер сможет работать только в активном режиме, 
## поэтому натим пакеты идущие от его 20 порта
nat on $ext_if inet proto tcp from $web_server port 20 to \
    !$int_if:network -> ($ext_if)
## натим пакеты на интерфейсе другого ISP(dc0), 
## идущие от прокси сервера одной из сетей
nat on $isp_if inet proto tcp from $proxy to !$web_server port www -> ($isp_if)
## Натим пакеты на интерфейсе dc0, идущие к mail серверам
nat on $isp_if inet proto tcp from $int_if:network to any port \
    { smtp, pop3 } -> ($isp_if)
## Разрешаем доверенным хостам ходить через дешевый интернет канал(dc0)
nat on $isp_if inet proto tcp from <servers> to any port www -> ($isp_if)

## запрещаем все входящие соединения на внешнем интерфейсе
block in on $ext_if
## На пинги отвечаем через тот же интерейс, откуда он пришел
pass in on $ext_if reply-to ($ext_if $ext_gateway) inet proto \
	icmp from any to $ext_if keep state
## отвечаем через тот же интерфейс, через который пришел пакет.
## по сути меняем для помеченный пакетов route.
pass in on $ext_if reply-to ($ext_if $ext_gateway) inet proto tcp \
    tagged WEB_SERVER keep state
pass in on $ext_if reply-to ($ext_if $ext_gateway) inet proto tcp \
    tagged FTP_SERVER keep state
pass in on $ext_if reply-to ($ext_if $ext_gateway) inet proto tcp \
    tagged SSH_SERVER keep state
pass in on $ext_if reply-to ($ext_if $ext_gateway) inet proto tcp \
    tagged VETEROK keep state
pass in on $ext_if reply-to ($ext_if $ext_gateway) inet proto tcp \
    tagged PINGUIN keep state
## Разрешаем все исходящие соединения на данном интерфейсе
pass out on $ext_if keep state

## Блокируем все входящие пакеты на внутреннем интерфейсе
block in on $int_if
## разрешаем входящие пакеты к squid
pass in on $int_if inet proto tcp from $int_if:network to $int_if \
    port 3128 keep state
## отправляем пакеты, идущие к внешним ssh серверам, по другому маршруту
pass in on $int_if route-to ($ext_if $ext_gateway) inet proto tcp from\
    $int_if:network to { !$int_if, !$web_server, !$proxy } port 22 tag SSH keep state
## разрешаем соединяться по ssh внутри сети
pass in on $int_if inet proto tcp from $int_if:network to \ 
    { $int_if, $web_server, $proxy } port 22 keep state
## куда же без dns? ;)
pass in on $int_if inet proto udp from $int_if:network to \
    $int_if port 53 keep state
## Разрешим сети соединяться с почтовыми службами
pass in on $int_if inet proto tcp from $int_if:network to any \
    port { smtp, pop3 } keep state
## Пускаем пакеты, идущие к внешним radmin серверам, метим их и меняем маршрут
pass in on $int_if route-to ($ext_if $ext_gateway) inet proto tcp from \
    $int_if:network to any port 4899 tag RADMIN keep state
## Разрешаем обращение к внутренним radmin сервера
pass in on $int_if inet proto tcp from $int_if:network to $pinguin \
    port 2004 keep state
## Разрешаем доверенным хостам соединяться с www серверами в обход прокси
pass in on $int_if inet proto tcp from <servers> to any port www keep state
## Пропускаем аську и меняем для нее маршрут
pass in on $int_if route-to ($ext_if $ext_gateway) inet proto tcp from \
	$int_if:network to any port 5190 tag ICQ keep state
## Разрешаем snmp запросы на внутреннем интерфейсе
pass in on $int_if inet proto udp from $mail to $int_if port snmp keep state
## разрешаем icmp пакеты. Как ни крути, но нужны они! ))
pass in on $int_if inet proto icmp from $int_if:network to $int_if keep state
## Разрешаем все исходящие соединения
pass out on $int_if keep state

## Запрещаем все входящие соединения на интерфейсе одного из провайдеров(dc0)
block in on $isp_if
## Разрещаем входящие соединения для пользователя proxy, 
## из-под него работает ftp-proxy
## Это альтернатива открытию всех портов, которые больше 49152
pass in on $isp_if inet proto tcp from any to $isp_if user proxy keep state
## И еще разок пинги.
pass in on $isp_if inet proto icmp from any to $isp_if keep state
## Разрешаем все исходящие пакеты
pass out on $isp_if keep state

## Блокируем все входящее
block in on $prov_if
## Разрешаем только пинги и...
pass in on $prov_if inet proto icmp from $prov_if:network to $prov_if keep state
## ... все исходящие соединения
pass out on $prov_if keep state

## Запрещаем на интерфейсе локальной сети -- dc2
block in on $iikt_if
## Разрешаем обращаться к нашему dns
pass in on $iikt_if inet proto udp from $pinguin to $int_if port 53 keep state  
## разрешаем запросы к squid'у
pass in on $iikt_if inet proto tcp from $iikt_if:network to \
    $iikt_if port 3128 keep state
## разрешаем пинги
pass in on $iikt_if inet proto icmp from $iikt_if:network to $iikt_if keep state
## разрешаем все исходящие
pass out on $iikt_if keep state

## на интерфейсе DMZ блочим все
block in on $dmz_if
## Меняем маршрут для пакетов, идущих от порта ftp-data ftp сервера.
pass in on $dmz_if route-to ($ext_if $ext_gateway) inet proto tcp from $web_server \
	port 20 to !$int_if:network keep state
## серверам в DMZ нужно общаться с dns
pass in on $dmz_if inet proto udp from $dmz_if:network to $dmz_if port 53 keep state
## Ну и информационные сообщения тоже не повредят
pass in on $dmz_if inet proto icmp from $dmz_if:network to $dmz_if keep state
## разрешаем все исходящие соединения
pass out on $dmz_if keep state

Вот такой вот конфиг. )) Вроде нормально прокомментирован. Если неохота заниматься копированием, то этот же конфиг лежит здесь.
Ну вот вроде и все что хотел рассказать. Про pf много чего рассказать можно, чем я и займусь в ближайшее время...



размещено: 2006-11-08,
последнее обновление: 2006-11-08,
автор: fr33man


eugene, 2006-11-28 в 21:23:23

сталкнулся с такой багой
при включеном pf и при высокой нагрузке
получаю сообщения No bufer space available

как лечить ?
sysctl крутил и все что можно увеличил (буферы и фсё такое)

fr33man, 2006-11-28 в 22:08:42

У меня было что-то похожее... Только не помню из-за pf или нет.. Короче, могу посоветовать две вещи:

1) Обновить систему. У меня при большо нагрузке система висла насмерть каждые 15 минут. Обновился до 6.1-p6, все стало нормально.

2) Навряд ли поможет, но попробуй увеличить кол-во max state в pf.

Удачи!

boroda, 2007-01-11 в 18:01:06

Добавил строчки в свой конфиг, но при загрузки pf,
пишет syntax error в строчках где nat.
как лечить?

OS FreeBSD 5.4

#interface
int_if_0="rl0"
ext_if_1="xl1"
ext_if_2="xl0"

#gateway
ext_gw_1="84.x.x.x"
ext_gw_2="195.x.x.x"


nat on $ext_if_1 inet proto tcp tagged IF_1 -> ($ext_if_1)
nat on $ext_if_2 inet proto tcp tagged IF_2 -> ($ext_if_2)

rdr on $ext_if_1 inet proto tcp to $ext_if_1 port $client_port tag IF_1 -> $client_addr port $client_port
rdr on $ext_if_2 inet proto tcp to $ext_if_2 port $client_port tag IF_2 -> $client_addr port $client_port

pass in on $ext_if_1 reply-to ($ext_if_1 $ext_gw_1) inet proto tcp tagged IF_1 keep state
pass in on $ext_if_2 reply-to ($ext_if_2 $ext_gw_2) inet proto tcp tagged IF_2 keep state

favourite, 2007-01-24 в 9:25:12

Битые ссылки в статье
http://fr33man.ru/other/pf.conf и http://fr33man.ru/images/topology.png

Bas, 2007-01-29 в 14:01:24

Да Да Лис поправь ссылочку пожалуйста на картиночку

freeman, 2007-03-18 в 20:39:49

Про pf много чего рассказать можно, чем я и займусь в ближайшее время... Ждём с нетерпением :)

artem, 2007-04-06 в 12:33:15


Вот эту не помешает! :-)

# Blocking Spoofed Packets
antispoof for { lo $int_if_OUTSIDE $int_if_DMZ_1 $int_if_DMZ_2 $int_if_DMZ_3 $int_if_DMZ_4 $int_if_DMZ_5} inet

# Passive Operating System Fingerprinting
block in quick from any os nmap to any
#block in quick from any os unknown to any

block in log-all all
block out log-all all

# PORT SCANNERS FOR OS DETECTING

block in log-all quick proto tcp from any to any flags /S
block in log-all quick proto tcp from any to any flags /SFRA
block in log-all quick proto tcp from any to any flags /SFRAU
block in log-all quick proto tcp from any to any flags A/A
block in log-all quick proto tcp from any to any flags F/SFRA
block in log-all quick proto tcp from any to any flags U/SFRAU
block in log-all quick proto tcp from any to any flags SF/SF
block in log-all quick proto tcp from any to any flags SF/SFRA
block in log-all quick proto tcp from any to any flags SR/SR
block in log-all quick proto tcp from any to any flags FUP/FUP
block in log-all quick proto tcp from any to any flags FUP/SFRAUPEW
block in log-all quick proto tcp from any to any flags SFRAU/SFRAU
block in log-all quick proto tcp from any to any flags SFRAUP/SFRAUP
block in log-all quick proto tcp from any to any flags SFUP/SFRAU
block in log-all quick proto tcp from any to any flags FPU/SFRAUP
block in log-all quick proto tcp from any to any flags F/SFRA
block in log-all quick proto tcp from any to any flags P/P

ekto, 2007-04-09 в 22:39:09

to Boroda
а что у вас собсно IF_1 и IF_2 ?

sergey, 2007-04-10 в 13:18:38

вот что то не пойму этот набор
запросы аська дает соединения отображает но не работает как я понимаю
исходящие есть запросы а входящих нет и не пойму почему объясните новичку?
nat on $ext_if inet proto tcp tagged ICQ -> ($ext_if)
pass in on $int_if route-to ($ext_if $ext_gateway) inet proto tcp from $int_if:network to any port 5190 tag ICQ keep state

s.romanov, 2007-04-12 в 9:10:33

ссылки по прежнему битые

vadiko, 2007-07-03 в 14:08:16

А вот Вам господа ссылочка на на занимательное чтиво пo пакетному фильтру на русском языке:
[url=http://house.hcn-strela.ru/BSDCert/BSDA-course/apc.html]

Ден, 2007-08-31 в 13:34:57

artem: А есть смысл прятать OS? ;) Нет, паранойя где-то хороша, но не на роутере, имхо.

ait, 2007-12-16 в 19:36:53

Согласен с Ден'ом, но информация всёж полезная.
Вопрос к автору - чем мотивируется применение stateful-правил? Не вызовет ли это большую нагрузку на систему? Не критикую, просто интересно ;)

artem, 2007-12-16 в 23:42:23

# Passive Operating System Fingerprinting
block in quick from any os nmap to any

Эта строка определяет сканер и рубит на всех интерфейсах
А если у Вас умный узверь и знает что такое nmap?

demodem10, 2008-01-16 в 14:33:44

ссылки битые Lis поправь плиз!

CrazyAdmin, 2008-02-29 в 0:38:47

Поправьте ссылку на схемку топологии

Kot_Off, 2009-02-05 в 13:03:34

Ссылку на топологию, плиззззз

Oleg104, 2009-05-07 в 11:42:06

Поправьте ссылку на схемку топологии
+1

ymsssg, 2009-06-16 в 13:40:38

А как надо подправить правила фаерволла в случае если у нас есть squid (стоит на шлюзе) и нужно часть тех, кто ходит в нет через squid, выпускать в нет через dc1 а не через дефолтный dc0 ?

Евгений, 2009-09-28 в 14:35:13

Кто у кого слизал статью ???

http://softez.org/showthread.php?t=2500

vix, 2009-10-10 в 14:49:11

> Кто у кого слизал статью ???
> http://softez.org/showthread.php?t=2500
Слизали по сццылке. На дату смотрим.)

Ivan_83, 2010-04-02 в 23:03:50

## разрешаем пинги
pass in on $iikt_if inet proto icmp from $iikt_if:network to $iikt_if keep state

Это далеко не только пинги разрешаются!!!

И кучу исходящих правил на интерфейсах можно заменить на одно:
pass out quick from (self) to any flags S/SA keep state

Тоже самое для блокировки входящего траффика по всем интерфейсам:
block in all

alik, 2011-09-17 в 21:55:57

Спасибо автору!
Какой раз настраиваю по этой статье и все замечательно.



 

  Этот информационный блок появился по той простой причине, что многие считают нормальным, брать чужую информацию не уведомляя автора (что не так страшно), и не оставляя линк на оригинал и автора — что более существенно. Я не против распространения информации — только за. Только условие простое — извольте подписывать автора, и оставлять линк на оригинальную страницу в виде прямой, активной, нескриптовой, незакрытой от индексирования, и не запрещенной для следования роботов ссылки.
  Если соизволите поставить автора в известность — то вообще почёт вам и уважение.

© lissyara 2006-10-24 08:47 MSK

Время генерации страницы 0.0712 секунд
Из них PHP: 41%; SQL: 59%; Число SQL-запросов: 77 шт.
У Вас отключено GZIP-сжатие в браузере. Размер страницы 60504