В некоторых случаях бывает полезно разделить одну физическую сеть на некоторые сегменты без создания подсетей и установки маршрутизаторов. Например для того, чтобы изолировать нагруженные трафиком участки сети. В дальнейшем будем рассматривать сеть на основе технологии Ethernet (Fast Ethernet)
Мост работает на канальном уровне, строя адресную таблицу на основе пассивного наблюдения за трафиком, циркулирующем в подключенных к нему сегментах. В эту таблицу заносятся MAC-адреса устройств и порт моста, к которому подключен сегмент с этими устройствами. Мост передает пакеты только в том случае, если в соответствии с его таблицей адрес источника и адрес назначения подключены к разным портам.
В настоящее время повсеместно используются многопортовые мосты -коммутаторы. На основе компьютера с двумя сетевыми картами можно тоже построить мост. Это позволяют сделать ОС FreeBSD и Linux. Однако эти ОС позволяют также создать мосты с фильтрацией - т.е. мост, помимо всего выполняющий и функции фильтра ip пакетов, или, как иногда его называют - firewall.
Где же может применяться такой фильтрующий мост? Первое и самое очевидное - при подключении к провайдеру. Вот пример - вам выделили диапазон ip-адресов и выдали ethernet подключение к маршрутизатору провайдера, к которому вы доступа не имеете и который не выполняет абсолютно никакой фильтрации, а вам необходимо защитить свои сервера, создать DMZ... Конечно, сразу напрашивается решение - поставить програмный маршрутизатор на основе FreeBSD, выполняющий фильтрацию. Однако тут обычно и бывают сложности. Во-первых, у вас сразу уменьшится число ip-адресов на 2, т.к. маршрутизатору нужен адрес на каждый интерфейс и вам придется перекраивать выделенный блок ip-адресов, чтобы получить сеть с нормальной маской (возможно, даже теряя адреса). Во вторых, для установки маршрутизатора необходимо, чтобы провайдер прописал его на своем маршрутизаторе, чтобы тот был в курсе, куда посылать пакеты для вашего блока ip-адресов. Вот тут и придет на помощь мост с фильтрацией.
Данную схему подключения можно изобразить следующим образом:
Или же вы просто хотите отгородить один из участков своей сети с фильтрацией проходящего в него и из него трафика.
К тому же мост имеет еще одно достоинство - ему не нужны ip-адреса. Его интерфейсы могут работать без назначения ip-адресов, что делает мост прозрачным. Однако, если вы хотите уметь к нему досуп, скажем, по ssh, а не только с консоли - можно назначить один ip-адрес на один из интерфейсов, что мы и сделаем.
Благодаря возможностям ipfw и dummynet вы сможете также ограничивать трафик, проходящий через мост.
Допустим, уже имеется машина с двумя сетевыми картами, доведенная до состояния STABLE (мы работали с версией 4 - RELENG_4), ядро которой уже было собрано с поддержкой сетевыйх карт. Для того, чтобы мост заработал, сетевые карты также должны поддерживать работу в "promiscuous" режиме. Для большей произоводительности желательно, чтобы это были PCI карты. Мы использовали две 3COM 3C905B-TX.
Добавим необходимые параметры в конфиг ядра:
options BRIDGE # Включим поддержку firewall options IPFIREWALL # для того, чтобы добавить возможность firewall вести логи # добавим параметр: options IPFIREWALL_VERBOSE # ограничим число пакетов, о которых ядро будет сообщать: options IPFIREWALL_VERBOSE_LIMIT=10
# Добавим еще парочку нужных параметров # ICMP_BANDLIM включает ограничение полосы для # ответов icmp error # Поскольку мы дадим мосту 1 ip-адрес, # этот параметр в некоторых случаях # помогает от D.O.S. атак. options ICMP_BANDLIM
# Добавим также параметр, который заблокирует # перезагрузку системы при нажатии Ctrl+Alt+Del options SC_DISABLE_REBOOT
После того, как необходимые парметры добавлены, пересоберем ядро (о том, как это сделать, можно прочитать тут: http://www.freebsd.org.ru/how-to/kernelconfig.html . Пример конфига ядра для нашей конфигурации с картами 3COM 3C905B-TX можно взять тут ).
Для того, чтобы запустить IPFirewall, необходимо добавить несколько параметров в /etc/rc.conf. Для начала опишем необходимые параметры, а затем приведем готовый фрагмент для вставки в rc.conf.
Прежде всего необходимо добавить параметр firewall_enable="YES". Параметр firewall_script="/etc/rc.firewall" укажет, какой скрипт будет запускаться для активизации правил firewall. Следующим параметром будет firewall_type. Этот параметр показывает, какой тип firewall будет использоваться из заранее приготовленных разработчиками (open, client, simple, closed) или же имя файла, из которого будут браться правила для firewall, если не подходит ни один из заранее приготовленных типов. Мы создадим файл ipfw.rules со своими собственными правилами, посему поставим firewall_type="/etc/ipfw.rules". Также необходим параметр firewall_quiet. Если его поставить в YES, то при загрузке будет отключен вывод на экран правил firewall. Однако для начала лучше ему дать значение NO, чтобы видеть активируемые правила при загрузке. Парметр firewall_logging установим в YES для того, чтобы велись логи. Поскольку у нас машина с двумя сетевыми картами и чтобы она вдруг не заработала как маршрутизатор поставим gateway_enable="NO"
Итого, у нас получилась следующая вставка в rc.conf:
Создадим и отредактируем файл /etc/ipfw.rules, который мы указали в параметрах в rc.conf. Поскольку в конфиг ядра мы не добавляли параметр IPFIREWALL_DEFAULT_TO_ACCEPT, то ipfw по умолчанию не зависимо от наших настроек будет добавлять в конец правило 65535 deny ip from any to any. Поэтому мы должны разрешить все необходимые сервисы в нашем файле.
Пусть у нас есть 2 интерфейса - xl0 и xl1. Для мостов приемлимым решением (а иногда и необходимым) является разрешение любого трафика на одном из интерфейсов и фильтрация входящего и исходящего на другом. Так и поступим - разрешим любой трафик на интерфейсе xl1, а фильтровать будем входящий на xl0.
При работе моста есть еще одна особенность. Дело в том, что для корректной работы ip протокола необходимо использование протокола ARP. Если пакеты этого протокола не будут проходит через мост, то станции по разные стороны моста не смогут передавать друг другу пакеты, т.к. не будет выполняться преобразование ip-адресов в mac-адреса сетевых карт. ipfw имеет возможность ограничивать ethernet-протоколы. Для этого создается специальное правило для udp пакетов с адресом источника 0.0.0.0, а порт источника будет показывать номер ethernet-протокола. Таким образом можно заставить мост пропускать или не пропускать протоколы, отличные от IP. Для вышеупомянутого протокола arp правило будет выглядеть следующим образом:
add allow udp from 0.0.0.0 2054 to 0.0.0.0
Поскольку мы решили помимо фильтрации также использовать traffic shaper dummynet, напишем правило, ограничивающее, например, весь проходящий icmp-трафик (входящий+исходящй) на 50Кб/с:
add pipe 1 icmp from any to any pipe 1 config bw 50Kbit/s queue 10
Заметим, что в случае написания других правил для shaper'а, включающих в себя адресаузлов, сетей - их нужно ставить в самое начало нашего файла ipfw.rules. ipfw устроен таким образом, что пакет проверяется по правилам сверху вниз и как только находится правило, которому он удовлетворяет - проверка на соответствие другим нижестоящим правилам не производится. Таким образом, если пакет будет удовлетворять правилу фильтрации - он может не дойти до правил traffic shaper'а. Однако если первыми стоят правила шейпера, то существует возможность пропустить пакет по правилам, котрые стоят ниже правил шейпера. Для этого нужно установить переменную net.inet.ip.fw.one_pass=0.
Добавим еще парочку правил, например, разрешающих прохождение входящего dns-трафика, обращений к web-серверу и icmp-трафика через интерфейс xl0. Также не забудем разрешить любой трафик через xl1:
add 1000 allow tcp from any to any in via xl0 established add 1200 allow tcp from any to any domain in via xl0 add 1300 allow udp from any to any domain in via xl0 add 1400 allow udp from any domain to any 1024-65535 in via xl0 add 1500 allow tcp from any to any www in via xl0 add 1600 allow icmp from any to any add 1700 allow ip from any to any via xl1
Итого, наш итоговый файл /etc/ipfw.rules получился следующим:
add pipe 1 icmp from any to any pipe 1 config bw 50Kbit/s queue 10 add 0900 allow udp from 0.0.0.0 2054 to 0.0.0.0 add 1000 allow tcp from any to any in via xl0 established add 1200 allow tcp from any to any domain in via xl0 add 1300 allow udp from any to any domain in via xl0 add 1400 allow udp from any domain to any 1024-65535 in via xl0 add 1500 allow tcp from any to any www in via xl0 add 1600 allow icmp from any to any add 1700 allow ip from any to any via xl1
Перезагрузимся, чтобы вступили в силу настройки rc.conf и загрузилось новое ядро.
По умолчанию мост не работает. Для его запуска необходимо установить параметры net.link.ether.bridge_ipfw (чтобы работала фильтрация) и net.link.ether.bridge(чтобы активировать мост) в 1. Также необходимо для одновременной работы шейпера и фильтрации переменную net.inet.ip.fw.one_pass установить в 0. Сделаем это из приглашения командной строки:
Все, мост работает. Для того, чтобы каждый раз после перезагрузки не надо было изменять значения переменных, добавим следующие строки в /etc/sysctl.conf (если нет такого файла - создайте его):
Итак, мост готов. МЫ провели примерные замеры производительности. Конфигурация: PIII-500MHz, 128Mb RAM, 2 сетевых интерфейса 3COM 3C905B-TX, 3 очереди для шейпера + фильтр на 30 правил. Результаты получились следующими: задержка в 0.2 ms при отсутствии трафика и 0.8 ms при интенсивном обмене.
Несколько замечаний по использованию мостов. Мосты не допускают создания архитектуры с петлями, поскольку в этом случае будет некорректно строится таблица соответствия моста. Если вы используете мост с фильтрацией, постарайтесь предусмотреть в правилах фильтра всё необходимое, иначе вы рискуете потратить много времени на поиск места, через которые не проходят нужные вам пакеты, особенно в больших сетях со сложной топологией. Мы также рекомендуем назначать на один из интерфейсов ip-адрес, чтобы иметь возможность настраивать его удаленно через ssh. И конечно, при использовании фильтрации, у вас должны быть открыты необходимые порты tcp для работы протокола ssh.
Родилось небольшое замечание - в список команд для запуска моста имхо стоит добавить согласно man sysctl -w net.link.ether.bridge_cfg=xl0:0,xl1:0 для перевода карт в promiscoius режим.