Статья моего знакомого Владимира Ляшко напечатанная в журнале
Поводом для написания данной статьи послужил реальный опыт настройки сетевого фильтрующего моста на связке if_bridge+IPFW. Для решения описываемой задачи это было самым простым и логичным решением.
Зачем нужен if_bridge?
В каких же случаях и для решения каких задач можно использовать фильтрующий мост на основе if_bridge и сетевого фильтра IPFW во FreeBSD? Вот несколько примеров:
Иногда возникает необходимость разделить одну физическую сеть на некоторые сегменты без создания подсетей и установки маршрутизаторов, в случае если вы хотите отгородить один из участков своей сети с фильтрацией проходящего в него и из него трафика.
Для создания собственно сетевого экрана в случае, когда на вашу сеть выделен диапазон ip-адресов и подключение к шлюзу провайдера, к которому вы не имеете доступа и который не выполняет никакой фильтрации, а вам необходимо установить собственные правила игры;
Если в локальной сети есть публичные сервера, например web или ftp и необходимо разделить их и локальную сеть на отдельные части, в целях безопасности, т.е. организовать DMZ — Demilitarized Zone. Как известно суть DMZ заключается в том, что она не входит непосредственно ни во внутреннюю, ни во внешнюю сеть и доступ к ней может осуществляться только по заранее заданным правилам межсетевого экрана. В случае, когда необходимо это реализовать без какого-то либо изменения адресного пространства сети, можно использовать фильтрующий мост на основе if_bridge.
Сразу кстати следует заметить, что максимальные возможности фильтрации представляются именно в связке if_bridge+IPFW, так как мост (сетевые интерфейсы моста) работает на канальном уровне, а брандмауэр IPFW может фильтровать на layer2. В моем случае необходимо было изолировать четыре машины из сегмента 192.168.1.0/24 большой локальной сети, имеющей доступ в мир через NAT шлюза провайдера, одной небольшой, но уважающей себя конторы. Проведя кабель к ближайшему свитчу и подключив эти машины через фильтрующий мост, я получил разделение сегмента сети без изменения сетевого пространства, единственное, что сделал провайдер по моей просьбе — зарезервировал (на шлюзе работал сервер DHСP) четыре ip-адреса, чтобы было легче писать правила пакетного фильтра. То есть моя задача сводилась к фильтрации входящего и исходящего трафика для диапазона из четырех ip-адресов участка сети, который будет находиться за фильтрующим мостом, на рисунке это PC5, PC6, PC7, PC8:
Настройка ядра и конфигурационные файлы
Теперь рассмотрим порядок настройки прозрачного моста — брандмауэра в операционной системе FreeBSD 7.0. Итак. Для поднятия моста if_bridge необходимо пересобрать ядро с параметром:
device if_bridge
или загрузить код драйвера при загрузке системы, для этого добавляем вот такие строки в /boot/loader.conf:
if_bridge_load=»YES»
bridgestp_load=»YES» — ставим “YES” для включения поддержки протокола STP, если присутствует кольцевая топология сети, основной задачей этого протокола является приведение сети Ethernet с множественными связями к древовидной топологии, исключающей циклы пакетов. Происходит это путем автоматического блокирования ненужных в данный момент для полной связности портов, про логику работы протокола можна почитать тут: http://www.nag.ru/2005/0517/0517.shtml
Параметры для поддержки ядром сетевого экрана IPFW:
options IPFIREWALL — включает в ядро код для фильтрации пакетов;
options IPFIREWALL_VERBOSE — включает возможность вести логи по правилам фильтрации и проходящих пакетов;
options IPFIREWALL_VERBOSE_LIMIT=10 — ограничение списка пакетов записываемых в лог для ограничения флуда на syslog и быстрого роста размера файла лога.
Для тех, кто впервые настраивает брандмауэр на основе IPFW, возможно, полезной будет опция: IPFIREWALL_DEFAULT_TO_ACCEPT, она добавляет разрешающее правило за номером 65000:
add allow ip from any to any
потому что без нее в итоге при перезагрузке системы мы получим firewall, который по умолчанию будет иметь одно запрещающее правило за номером 65535:
deny ip from any to any
которое закроет прохождение любого IP трафика по всем интерфейсам, что может вызвать проблемы при удаленном администрировании.
Собираем ядро, делая, как пишется в handbook:
http://www.freebsd.org/doc/ru_RU.KOI8-R/books/handbook/kernelconfig-building.html
#cd /usr/src/sys/i386/conf
#mkdir /root/kernels
#cp GENERIC /root/kernels/MOST
#ln –s /root/kernels/MOST
Правим конфиг нового ядра:
#ee MOST
Собираем:
#cd /usr/src
#make buildkernel KERNCONF=MOST
Инсталлируем новое ядро:
#make installkernel KERNCONF=MOST
Настраиваем параметры загрузки брандмауэра IPFW, редактируя файл /etc/rc.conf:
firewall_enable=”YES” – требуется как для загрузки IPFW в виде модуля (иначе запускать придется вручную), так и для IPFW, компилированном в ядро. “YES” установит значение системной переменной sysctl net.inet.ip.fw.enable=1, что укажет системе, использовать IPFW или нет, без скрипта с набором правил firewall загрузится с одним правилом по умолчанию;
firewall_logging=”YES” – включаем возможность логирования прохождения пакетов через брандмауэр, системная переменная sysctl net.inet.ip.fw.verbose=1, лог по умолчанию будет писаться в файл /var/log/security;
firewall_script=”/etc/ip.rules” – будем писать собственный скрипт с набором правил.
Для поднятия if_bridge добавляем следующие строки, назначая для одного сетевого интерфейса сетевой адрес для возможности удаленного администрирования как рекомендуют нам здесь: http://www.freebsd.org/doc/ru_RU.KOI8-R/books/handbook/network-bridging.html
ifconfig_nfe0=”inet 192.168.1.179 netmask 255.255.255.0”
ifconfig_rl0=”up”
cloned_interfaces=”bridge0”
ifconfig_bridge0=”addm rl0 addm nfe0 up”
Перегружаемся.
#reboot
Смотрим по выводу ifconfig, поднялся ли наш мост: должны появиться строки member с нашими сетевыми картами
# ifconfig
rl0: flags=8943 metric 0 mtu 1500
options=8
ether 00:e0:4c:50:31:2d
media: Ethernet autoselect (100baseTX )
status: active
nfe0: flags=8943 metric 0 mtu 1500
options=8
ether 00:1d:92:3f:e0:f2
inet 192.168.1.179 netmask 0xffffff00 broadcast 192.168.1.255
media: Ethernet autoselect (100baseTX )
status: active
plip0: flags=108810
metric 0 mtu 1500
lo0: flags=8049 metric 0 mtu 16384
inet6 fe80::1%lo0 prefixlen 64 scopeid 0x4
inet6 ::1 prefixlen 128
inet 127.0.0.1 netmask 0xff000000
bridge0: flags=8843 metric 0 mtu 1500
ether 5e:79:06:7c:cb:5e
id 00:00:00:00:00:00 priority 32768 hellotime 2 fwddelay 15
maxage 20 holdcnt 6 proto rstp maxaddr 100 timeout 1200
root id 00:00:00:00:00:00 priority 32768 ifcost 0 port 0
member: nfe0 flags=143
member: rl0 flags=143
Устанавливаем и проверяем следующие значения переменных системы:
#sysctl net.link.ether.ipfw=1 – переменная относится к опциям работы IPFW, значение равное единице включает возможность фильтрации IPFW на канальном уровне;
#sysctl net.link.bridge.ipfw=1 – имеет смысл только при использовании if_bridge, для реализации фильтрации мостом на канальном уровне необходимо установить значение равное единице, при условии что переменная net.link.ether.ipfw имеет такое же значение;
#sysctl net.link.bridge.pfil_member=0 включает возможность фильтрации на сетевых интерфейсах моста, в нашем случае пакеты будут идти транзитом, через поднятый bridge0 и при написании правил будем описывать именно этот интерфейс, поэтому ставим значение в ноль. При тестировании правил брандмауэра было обнаружено, что если поставить значение net.link.bridge.pfil_member=1 параметр via в правилах firewall будет работать только с “member” сетевыми картами, а параметр вида via bridge0 нет.
Остальные переменные системы относящиеся к if_bridge у меня имели такой вид:
#sysctl -a | grep bridge
net.link.bridge.ipfw: 1
net.link.bridge.log_stp: 0
net.link.bridge.pfil_local_phys: 0
net.link.bridge.pfil_member: 0
net.link.bridge.pfil_bridge: 0
net.link.bridge.ipfw_arp: 0
net.link.bridge.pfil_onlyip: 0
Чтобы после перезагрузки сохранились значения этих переменных необходимо прописать их в /etc/sysctl.conf.
Настройка правил для Firewall
Для начала вспомним три главных правила, которые определяют порядок прохождения пакетов и логику работы IPFW:
— пакет, попадая в firewall IPFW, следует согласно порядку расположений его правил до первого удовлетворяющего, где над этим IP-пакетом, согласно данному правилу, совершаются какие-либо действия (пропускается, отбрасывается, возвращается обратно в firewall и т.д.)
— входящие (IN) и исходящие (OUT) пакеты следует рассматривать относительно операционной системы, а не относительно сетевых интерфейсов.
— каждый маршрутизированный IP-пакет попадает в firewall как на входе в операционную систему, так и не выходе из неё:
Теперь пишем скрипт с правилами для нашего firewall
#!/bin/sh
#объявляем переменные
fwcmd=»/sbin/ipfw»
mylan=»192.168.1.203, 192.168.1.201, 192.168.1.202, 192.168.1.200″
macpc1=00:17:31:a9:e9:9b
macpc2=00:0c:42:1c:09:bd
macpc3=00:1d:92:3f:e0:f2
macpc4=00:e0:4c:50:31:2d
macgate=00:0e:2e:a9:6f:9e
#mac адрес сетевого интерфейса моста, которому мы присвоили IP адрес
ipbridge=00:50:da:4e:ba:63
#сбрасываем все правила
${fwcmd} -f flush
#проверяем, соответствует ли пакет динамическим правилам
${fwcmd} add check-state
#разрешаем все установленные соединения
${fwcmd} add allow tcp from any to any established
#разрешаем работу протоколу ARP
${fwcmd} add allow all from any to any layer2 mac-type arp
#так как у нас есть возможность фильтровать пакеты на канальном уровне, воспользуемся этим: #разрешаем трафик только от наших машин к роутеру провайдера и обратно
${fwcmd} add allow all from any to any MAC $macpc1 $macgate
${fwcmd} add allow all from any to any MAC $macgate $macpc1
${fwcmd} add allow all from any to any MAC $macpc2 $macgate
${fwcmd} add allow all from any to any MAC $macgate $macpc2
${fwcmd} add allow all from any to any MAC $macpc3 $macgate
${fwcmd} add allow all from any to any MAC $macgate $macpc3
${fwcmd} add allow all from any to any MAC $macpc4 $macgate
${fwcmd} add allow all from any to any MAC $macgate $macpc4
#блокируем весь трафик на lo0
${fwcmd} add deny all from any to 127.0.0.0/8
${fwcmd} add deny all from 127.0.0.0/8 to any
#блокируем мультикастовые рассылки
${fwcmd} add deny all from any to 240.0.0.0/4
#Запрещаем фрагментированные пакеты icmp
${fwcmd} add deny log icmp from any to 255.255.255.255
#запрещаем адреса которые используются в протоколах автоконфигурации
${fwcmd} add deny ip from 169.254.0.0/16 to any
#разрешаем http трафик
${fwcmd} add allow ip from $mylan to any 80 via bridge0 keep-state
#разрешаем DNS трафик
${fwcmd} add allow ip from $mylan to any 53 via bridge0 keep-state
#разрешаем вход по ssh c хоста 192.168.1.200 нашей сети
${fwcmd} add allow ip from $mylan to me 22 keep-state
${fwcmd} add allow all from any to any MAC $macpc1 $ipbridge
${fwcmd} add allow all from any to any MAC $ipbridge $macpc1
#разрешаем синхронизацию времени
${fwcmd} add allow udp from any to any 123 keep-state
#разрешаем ftp трафик (активный режим)
${fwcmd} add allow tcp from $mylan to any 21 via bridge0
${fwcmd} add allow tcp from any 20 to $mylan via bridge0
#разрешаем icmp – эхо-запрос, эхо-ответ и время жизни пакета истекло
${fwcmd} add allow icmp from any to any icmptypes 0,8,11 via bridge0
#разрешаем работать с почтой
${fwcmd} add allow tcp from $mylan to any 110,143,25,995 keep-state
#разрешаем icq
${fwcmd} add allow ip from $mylan to any 5190 keep-state
#блокируем весь трафик не с наших МАС адресов
${fwcmd} add deny all from any to any layer2
#это правило добавится автоматически
${fwcmd} add deny all from any to any
Следует отметить, что это только пример, так что какие правила писать в вашем конкретном случае, решать вам. Также следует заметить, что в данном случае (всего четыре компьютера) фильтрующий мост никак не виден в сети, задержки при прохождении пакетов через мост минимальны и ими можно пренебречь.
Литература:
1. man if_bridge
2. man ipfw
3. FreeBSD HandBook
4. Заметки об IPFW http://www.lissyara.su/?id=1536
//
Если есть возможность и желание, протестируйте пожалуйста загрузку системы в моменты, когда передаются пакеты со скоростью 100Мбит/с.
//
нет такой возможности, скажу точно — при трафике в мир около 4Мб/с, никаких задержек нет, загрузка системы мизерная.
//
370 мбит, загрузка 30% на core2
//
Интересная статья ! у меня сейчас такая же задача отгородить часть сети. Скажу сразу в FreeBSD не шарю. Начал заниматься эти вопросом нашел несколько дистрибов m0n0wall и pfsense. В описании указано что данные дистрибы можно привести в режим прозрачного моста. Я разобраться с этим так и не смог. И вообще я ни понимаю как может работать устройство которое имеет сетевой интерфейс но не имеет IP адреса. Ну то что оно работает используя мак адреса это понятно. Ну как на него за рулить трафик с маршрутизатора ?
//
Так в этом и суть, нет IP мост прозрачный, его не видно.
//
Скажите пожалуйста, а можно ли таким способом поставить на бриджевую FreeBSD например Squid, и правилами IPFW направлять на него проходящий мимо трафик?
//
Можно конечно 🙂