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

Модераторы: flash, mordor

Ответить
Аватара пользователя
flash
Сообщения: 16
Зарегистрирован: 08 ноя 2007, 16:13

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

Сообщение flash »

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

pf_enable="YES" # Enable PF (load module if required)
pf_rules="/etc/pf.conf" # rules definition file for pf
pf_flags="" # additional flags for pfctl startup
pflog_enable="YES" # start pflogd(8)
pflog_logfile="/var/log/pflog" # where pflogd should store the logfile
pflog_flags="" # additional flags for pflogd startup

соберем собственное ядрышко, добавив туда следующие опции:
device pf
device pflog
device pfsync
options ALTQ
options ALTQ_CBQ
options ALTQ_RED
options ALTQ_RIO
options ALTQ_HFSC
options ALTQ_CDNR
options ALTQ_PRIQ
options ALTQ_NOPCC


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

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
Вот такой вот конфиг. )) Вроде нормально прокомментирован
У вас нет необходимых прав для просмотра вложений в этом сообщении.
лучший Linux это Freebsd
Ответить