FreeBSD. Настройка FireWall. Часть 3.
Настройка FireWall
Кроме высокой надежности и производительности, операционная система FreeBSD славится и своим firewall'ом - удобным и понятным средством работы с протоколом TCP/IP. Далее по тексту я буду довольно свободно кидаться словами "адрес", "порт", "icmp" и т.д., поэтому тем, для кого эти слова звучат уж очень непонятно, рекомендую сначала ознакомиться с TCP/IP. Для нас же будет важно, в основном, только то, что в заголовке каждого ip-пакета имеются 32-битные адреса источника и назначения, а в пакетах протоколов UDP и TCP так же номера портов источника и назначения пакета. Из вышеперечисленных только TCP является протоколом с установлением соединения, и требует пересылки нескольких специальных пакетов для установления соединения перед началом полезной передачи данных.
Firewall - это система, управляющая прохождением пакетов данных через систему на основе заданных администратором правил и информации, содержащейся в заголовках пакетов. Обычное использование firewall - запрещение прохождения нежелательных пакетов, например, отключение абонента, не оплатившего услуги связи, или закрытие части сервисов локальной сети от внешнего мира. В системе FreeBSD firewall - это гораздо больше, чем просто турникет в метро - это мощный инструмент управления сетью, позволяющий, например, подсчитывать трафик по любым разумным правилам, основывающимся на данных заголовков пакетов протоколов стека TCP/IP, обрабатывать пакеты внешними программами, прятать за одним компьютером целую сеть и т.п.
В отличие от разнообразных систем firewall для операционных систем семейства Windows, во FreeBSD firewall является частью самой операционной системы, поэтому работает значительно быстрее и надежнее своих не-UNIX конкурентов (исключая, конечно, системы, созданные специально для обработки сетевого трафика, такие как Cisco IOS). Но т.к. firewall нужен далеко не на каждом компьютере с FreeBSD (ведь FreeBSD - это еще и высокопроизводительный файл-сервер, быстрый и надежный сервер приложений, мощная рабочая станция), то поддержка firewall не включена в ядро FreeBSD по умолчанию.
Мы уже собирали ядро с поддержкой firewall в первой главе, но теперь остановимся на опциях ядра подробнее:
|
И несколько опций, не относящихся к firewall напрямую, но чтобы уже больше не возвращаться:
|
Как работает firewall
Firewall - это защитная стена, стоящая между сетевым адаптером и операционной системой. Любой IP-пакет, прежде чем попасть на обработку операционной системой (например, для маршрутизации или передачи его web-серверу) проходит через строгий контроль. Любой исходящий пакет так-же наталкивается на эту стену, и может быть пропущен, отброшен, сосчитан или изменен. Если пакет проходит через операционную систему насквозь (маршрутизируется), то его проверка происходит как на входе, так и на выходе. При сложной обработке пакета он может проходить через firewall и большее число раз.
Проверка пакета производится по упорядоченному списку правил, которые задаются администратором. Каждому правилу присваивается номер (либо вручную администратором, либо автоматически), и правила проверяются строго в порядке возрастания номеров. Несколько правил могут иметь один и тот же номер - в этом случае они проверяются в том порядке, в котором они были занесены в список. Каждое правило содержит условие и действие. Вот общий вид правила firewall:
<номер> <номер> [prob <число>] <действие> [log [loamount <число>]] <протокол> from <откуда> to <куда> <дополнительные условия>
<куда> <дополнительные условия>
где:
<номер> - целое число в диапазоне от 1 до 65535. Правило с номером 65535 всегда существует, его нельзя удалить, и оно определяется параметром ядра IPFIREWALL_DEFAULT_TO_ACCEPT, разрешая или запрещая весь IP-трафик в зависимости от наличия этого параметра. Правила с другими номерами полностью управляются администратором.
prob <число> - Действие применяется с некоторой вероятностью. Данная возможность используется весьма редко. С помощью этого указания можно симулировать, например, нестабильную линию, или разное время прохождения пакетов. <число> в данном случае - вещественное, в диапазоне от 0 до 1 (0-правило не исполняется никогда, 1 - всегда).
<действие> - одна из следующих команд:
|
- если ядро скомпилировано в опцией IPFIREWALL_VERBOSE, то в системный журнал будет записан отчет о прохождении пакетом этого правила. Данная возможность может оказаться весьма полезной, если Вы ожидаете атаки хакера или отлаживаете сложный набор правил, разобраться в котором вручную не хватает сил. В журнал записывается время, номер правила и адреса источника и назначения пакета. logamount - максимальное количество пакетов, запись о которых попадает в журнал. По умолчанию устанавливается равным значению опции IPFIREWALL_VERBOSE_LIMIT в ядре операционной системы.
Действие будет предпринято, если пакет удовлетворяет следующим условиям:
<протокол> - название протокола, к которому относится данный пакет. Возможные значения - ip или all (для всех протоколов стека TCP/IP), udp, tcp, icmp, igmp и т.д. Полный список доступных для указания протоколов Вы можете посмотреть в файле /etc/protocols.
from <откуда> - IP-адрес источника пакета. Для протоколов TCP и UDP так же может быть указан и порт. Может быть указан IP-адрес, доменное имя компьютера (типа www.hub.ru), или целая подсеть в формате IP:MASK или IP/LEN, например 192.168.0.0:255.255.255.0 или 192.168.0.0/24. Есть так же два специальных слова - any, означающее любой адрес (аналогично 0.0.0.0/0) и me, означающее любой из адресов, принадлежащих локальной системе. Номер порта указывается после адреса через пробел. Несколько номеров портов можно указать через запятую. Перед адресом или номером порта может стоять слово "not", инвертирующее значение адреса или порта, т.е. from not 192.168.0.0/24 означает "все пакеты, пришедшие не из сети 192.168.0.0/24".
to <куда> - Адрес назначения пакета. Формат адреса аналогичен предыдущему.
Из дополнительных условий самыми нужными и часто используемыми являются направление пакета (входящий или исходящий) и сетевой интерфейс, при прохождении через который был "пойман" пакет. Формат указания направления и интерфейса следующий:
<правило...> [in|out] [via <интерфейс>]
где in или out - направление пакета (входящий и исходящий) по отношению к операционной системе, интерфейс - название устройства (rl0, lo0, etc) или IP-адрес этого устройства (192.168.0.1, 127.0.0.1, etc).
Управление firewall производится с помощью программы /sbin/ipfw, позволяющей удалять и добавлять правила, управлять настройками dummynet, снимать и обнулять статистику. Команда может вызываться со следующими наборами параметров:
/sbin/ipfw [-adetN] list [число...] - показать текущий список правил. Ключи команды имеют следующие значения:
|
/sbin/ipfw [-q] add правило - добавляет правило в список. Если в теле правила не указан его номер, то он будет вычислен как номер последнего правила в списке + 100. Флаг -q отключает вывод на экран подтверждающего сообщения, что весьма полезно при задании большого количества правил из скрипта (например, при старте системы).
/sbin/ipfw delete номер правила - удалить правило с заданным номером. Если в списке существует несколько правил с данным номером - будут удалены все.
/sbin/ipfw [-q] zero [номер правила] - обнуляет счетчики статистики для выбранного правила, или для всех правил, если номер не указан.
/sbin/ipfw [-i] resetlog [номер правила] - обнуляет счетчик попавших в журнал записей о срабатывании правила (если включена опция IPFIREWALL_VERBOSE_LIMIT=XXX). Если журнал ведется для мониторинга попыток хакерских атак, то полезно периодически выполнять эту команду для продолжения ведения журнала.
/sbin/ipfw [-f | -q] flush - полная очистка списка правил. Опция -f избавляет от вопроса "Действительно ли Вы хотите все удалить", и опция -q, кроме того, подавляет и вывод на экран подтверждающего сообщения.
/sbin/ipfw { pipe | queue } номер config опции - конфигурирование канала или очереди dummynet. О конфигурировании dummynet - попозже.
Вышеперечисленных возможностей достаточно для конфигурирования работоспособного firewall'а (но посмотреть man ipfw все-же рекомендую :) ), поэтому предлагаю перейти к рассмотрению примера, конфигурирующего наш сервер для предоставления пользователям сети 192.168.0.0/24 доступа в сеть Интернет, защищающего сервер от нежелательных соединений из внешнего мира, и предоставляющего доступ администратору сервера для конфигурирования системы из любой точки мира. Итак, попробуем переписать содержимое нашего файла /usr/local/billing/rc.firewall пользуясь имеющимися знаниями:
#!/bin/sh |
Пример, скорее, иллюстративный, чем "промышленный", однако волне работоспособный, и на его основе мы попытаемся разобраться с общими принципами построения списков правил firewall.
Рассмотрим предложенный пример по порядку, опустив пока строки 100,310 и 330, содержащие пока не известные нам слова ckeck-state и keep-state. В первых строках задаются значения переменных командного интерпретатора, описывающие соответственно, клиентскую сеть (ournet), общую часть всех адресов наших клиентов (uprefix), название "внешнего" и "внутреннего" интерфейсов (ifout и ifuser) Такие переменные позволят избежать случайных опечаток, и позволят легко изменить на строку firewall в случае, например, выхода из строя сетевой карты, и замены ее на сетевую карту другого производителя (в этом случае название внешнего интерфейса может смениться, например, на fxp0 для карт Intel EtherExpress).
Правила с номерами 200 и 210 служат для повышения хакероустойчивости системы: правило 200 запрещает появление пакетов с адресом, принадлежащим внутренней сети, на "внешнем" интерфейсе, т.к. любимое оружие хакера - представить свой "смертельный" пакет как-бы пришедшим из локальной сети, для которой степень доверия выше. Правило 210 запретит прохождения некоторых ICMP-пакетов: icmptype 5 - это пакет ICMP-REDIRECT, который может быть использован при атаке типа "фальшивый маршрутизатор", остальные icmptype - просто раскроют хакеру некоторую "лишнюю" с нашей точки зрения информацию... Сюда же можно добавить другие защитные правила - любой "гуру" насыпет их Вам с три короба.
Правила 300-350 обеспечивают работоспособность самой системы. Правило 300 разрешает прохождение любых пакетов внутри системы (lo - локальный интерфейс системы, имеющий адрес 127.0.0.1. Используется системой для обращения к себе самой). 320 правило разрешает прохождение любых ICMP-пакетов, т.к. их возникновение плохо предсказуемо, но их потеря грозит сбоями в работе - например, icmp-пакет является единственным способом сообщить "вызывающему" компьютеру, что "вызываемый" адрес не доступен. Правило 340 разрешает прохождение пакетов DNS из внешнего мира на сервер (me - все локальные адреса сервера). Это имеет смысл, если сервер является DNS-сервером, поддерживающим одну или несколько DNS-зон для сети Интернет - например, зону Вашей сети. Если Вы не регистрировали для Вашей сети домен, то это правило можно убрать. Правило 350 разрешает серверу посылать любые пакеты куда угодно - сами себе то мы доверяем, не правда ли?
Правила 400 и 410 разрешают пользоваться некоторыми сервисами, предоставляемым системой. Правило 400 разрешает всем (и пользователям локальной сети, и Интернету) подключаться к Web-серверу (у Вас же есть Web-сервер, рекламирующий Вашу сеть... кроме того, пользователь должен иметь возможность узнать состояние своего счета вне зависимости от того, оплачен у него "Интернет", или нет), и к службе SSH (Secure SHell - защищенная консоль, используемая для удаленного управления системой). Правило 410 разрешает прием входящей электронной почты, если у Вас установлен почтовый сервер.
Правила 500 и 510 обеспечивают дополнительную обработку пользовательского трафика. Правило 500 "заворачивает" весь http-трафик на локальный прокси-сервер (если он есть, если нет - то и правило не нужно). Правило 510 отправляет весь исходящий трафик пользователей на "переработку" системе NAT для трансляции адресов.
Правила 10ХХ управляют доступом в Интернет отдельных пользователей. Пользователю с адресом 192.168.0.2 соответствуют два правила с номером 1002, разрешающие прохождение любого трафика к пользователю и от пользователя. Если Вы хотите "отключить" пользователя (например, за неуплату) - просто удалите эти правила (одной командой - /sbin/ipfw delete 1002), и пользователь сможет работать только с вашим собственным Web-сервером...
Теперь о правилах с загадочными словами keep-state. Мы, очевидно, не хотим, чтобы хакеры из Интернета свободно подключались к любым портам сервера и делали свое черное дело. С другой стороны, весьма желательно, чтобы наш сервер мог соединяться с любой машиной в Интернете. Однако, не существует способа по содержимому одного единственного IP-пакета определить, инициировано соединение нашей системой, или "врагом". Правило с пометкой keep-state позволяет запомнить удовлетворяющее правилу соединение на некоторое время: если пакет соответствует правилу keep-state, то firewall создает динамическое правило, разрешающее прохождение пакетов между адресами, указанными в первом пакете. Последующие пакеты продляют жизнь временного правила еще на некоторое время. Если активность соединения прекращается - правило из списка исчезает, и соединение рвется.
Правило 310 разрешает прохождение TCP-пакетов с локальной машины на любую другую машину, запоминая соединение во временном правиле. Таким образом, разрешается прохождение и "обратных" пакетов от "вызванной" машины. Временные правила проверяются firewall'ом при прохождении через правило check-state - поэтому мы и поместили его на первое место. Ознакомиться с текущим списком динамических правил Вы можете, введя команду ipfw -d list.
Попробуем теперь рассмотреть прохождение нескольких пакетов через firewall.
Пусть пользователь 192.168.0.2 желает посмотреть страницу www.hub.ru (считаем, что на сервере работает transparent-proxy и DNS). Первым делом пользователь посылает DNS-запрос - UDP-пакет на адрес сервера (192.168.0.1) на порт 53 (domain). Правила 100-330 пакет проходит не задерживаясь, т.к. он им не удовлетворяет. Правило 340 разрешает прохождение пакета с любого адреса на локальный DNS, поэтому путь запроса на этом оканчивается. Ответ локального DNS-сервера - UDP-пакет с адреса 192.168.0.1, порт 53, на адрес 192.168.0.2 (порт - что-то вроде 1025, первый попавшийся под руку компьютеру пользователя), проходит по правилу 350, разрешающему прохождение любых пакетов сервера куда угодно. Если в кэше локального DNS-сервера не найдется записи о сервере www.hub.ru, то он вынужден будет послать запрос своему вышестоящему DNS-серверу - UDP-пакет с адресом источника 193.232.100.100 на адрес 195.34.32.10 (для примера взят DNS-сервер MTU), который пройдет по правилу 330, породив временное правило, разрешающее прохождение обратного пакета.
Следующим этапом открытия страницы будет TCP-соединение с сервером www.hub.ru на порт 80 (http). Пользователь, получивший от DNS-сервера IP-адрес сервера www.hub.ru (195.54.192.86) пошлет TCP-пакет с адресом отправителя 192.168.0.2 (порт типа 1026) и адресом назначения 195.54.192.86, порт 80. Этот пакет пройдет по firewall до правила 1002, разрешающего пользователю любой трафик, после чего попадет в систему маршрутизации, которая попытается отправить его через внешний интерфейс - т.е. снова попадет в firewall, но уже как исходящий. В этом своем втором путешествии он доберется до правила 500, где его адрес назначения будет переправлен на 127.0.0.1, порт 3128, после чего он попадет в proxy-сервер. Proxy-сервер сгенерирует ответный пакет, с адресом назначения 192.168.0.1, который по правилу 350 будет отправлен пользователю. После того, как proxy-сервер поймет, какую именно страницу хочет получить пользователь (для этого пользователю и proxy-серверу придется обменяться еще несколькими пакетами по той-же схеме), proxy начнет собственное tcp-соединение с сервером www.hub.ru - отправит tcp-пакет с адреса 193.232.100.100 на адрес 195.54.192.86, порт 80. Этот пакет пройдет по правилу 310, породив динамическое правило. Ответ от www.hub.ru будет пропущен этим динамическим правилом при проверке правила с номером 100 - check-state.
Следующий пример - обращение пользователя к внешнему ftp-серверу, например - ftp.freebsd.org. DNS-запрос на разрешение доменного имени пройдет аналогично предыдущему примеру, возвратив пользователю IP-адрес 62.243.72.50. Получив адрес сервера пользователь пошлет на него tcp-пакет, который будет соответствовать правилу 1002, и попадет в маршрутизатор, который попытается отправить его через внешний интерфейс.
При попытке "выбраться" из системы пакет дойдет до правила 510, которое "завернет" пакет на обработку natd, и выйдет из системы c адресом источника, равным нашему "внешнему" адресу - 193.232.100.100. При этом natd запомнит во временном правиле настоящий источник пакета, и пришедший ответный пакет будет передан пользователю, пройдя через разрешающее правило 1002.
Замечание для критиков - да, я знаю, что всё это можно организовать немного эффективнее, в частности без динамических правил - но данный пример создан в иллюстративных целях. Для желающих сделать всё максимально эффективно в Интернете есть множество примеров настроек (часто противоречащих друг-другу), однако динамические правила я все-же счел нужным описать.
Дополнительной возможностью, предоставляемой динамическими правилами, является возможность ограничения числа одновременных соединений, соответствующих какому-то правилу (это может пригодиться, если Вы захотите бороться с "левыми" прокси-серверами в вашей сети - для нормальной работы пользователя вполне достаточно десятка одновременных соединений, в то время как для прокси-сервера такое количество является явно недостаточным). Для ограничения соединений добавьте к "генерирующему" правилу параметр limit, например:
/sbin/ipfw add allow ip from 192.168.0.1/24 to any keep-state limit src-addr 10
запретит каждому абоненту сети 192.168.0.1:255.255.255.0 устанавливать более 10 соединений одновременно. Параметр src-addr указывает, что ограничение считается по адресам источников пакетов (т.е. в нашем примере - для каждого пользователя). Допустимые значения этого параметра: dst-addr (ограничение подсчитывается по адресам назначения), src-port (ограничение подсчитывается по портам источника), dst-port (ограничение подсчитывается по портам назначения), а также любые комбинации этих параметров, например, limit dst-port dst-addr 1 позволит установить только одно соединение с любым портом любого сервера, при этом можно будет установить несколько соединений с одним сервером (например, HTTP, SMTP и POP3 одновременно) и несколько соединений на один порт различных серверов (например, одновременно скачивать www.anekdot.ru и www.hub.ru).
Ограничение скорости
Firewall позволяет Вам не только разрешать или запрещать прохождение IP-пакетов, но и ограничивать скорость их прохождения. Для этого используется встроенная в ядро FreeBSD система dummynet - эмулятор "плохой" линии связи с настраевыми характеристиками, такими как абсолютная задержка прохождения пакета, ограничение скорости прохождения данных по линии, потеря некоторого числа пакетов.
Dummynet состоит из каналов (pipe, труба) и очередей (queue). Канал характеризуется пропускной способностью (биты в секунду), задержкой прохождения пакета (в секундах), размером очереди (сколько данных может одновременно "находится" в канале), процентом потерь. Задать эти значения Вы можете с помощью команды
/sbin/ipfw pipe <номер> config bw <скорость> delay <время> queue <очередь> plr <процент>
, где <номер> - номер канала. Выбирается администратором произвольно из диапазона 1-65534
<скорость> - пропускная способность канала. Задается в виде числа, интерпретируемого как биты в секунду. Возможно также задание и единицы измерения из следующего набора: bit/s, Kbit/s, Mbit/s, Bytes/s, KBytes/s,MBytes/s. Единицы измерения указываются после числа без пробелов: 2MBytes/s, 64Kbit/s.
<время> - время задержки пакета в миллисекундах, всегда прибавляется к времени нахождения любого пакета в канале в не зависимости от текущей загрузке канала.
<очередь> - размер очереди в пакетах или в килобайтах (если указана единицы измерения - Bytes или KBytes). Не поместившиеся в очередь пакеты отбрасываются.
<процент> - процент потерянных пакетов. Обычно используется для эмуляции плохих линий связи при проверке устойчивости сетевого программного обеспечения к сбоям. Задается как вещественное число от 0 до 1 (0 - потерь нет, 1 - теряются все пакеты).
Для управления каналом нужно представлять себе, как он работает - иначе неминуемы нестыковки и неприятные разочарования. При поданании в канал пакет "становится в хвост" очереди - совсем как в магазине. Dummynet определенное количество раз в секунду (задается параметром HZ при сборке ядра операционной системы) проверяет наличие пакетов в очереди, и, если не превышен лимит скорости выхода данных из канала, выпускает пакет. Считается именно скорость схода пакетов с канала - поэтому если пакеты в очередь поступают с большей скоростью, чем разрешенная для данного канала скорость выхода из очереди, то "непоместившиеся" в очередь пакеты просто теряются (не встанете же Вы в очередь за хлебом, если перед Вами уже 50 человек, а продавец обслуживает клиентов очень медленно).
Для пользователя, если он работает по протоколу TCP, потери пакетов не заметны - сервер перестает посылать пакеты, если клиент не посылает подтверждение приема. Однако, ожидание подтверждения на каждый пакет понижает производительность - канал связи может обеспечивать большую пропускную способность при достаточно большом времени прохождения пакета, и если ждать ответа на каждый пакет, то канал будет простаивать. Поэтому в протоколе TCP используется метод окна - посылаются сразу несколько пакетов подряд без ожидания подтверждения, и посылка пакетов прекращается только в том случае, если подтверждение не пришло еще на поза-поза-прошлый пакет.
Чтобы работа по протоколу TCP через канал dummynet происходила без необходимости повторной пересылки пакета, необходимо чтобы все пакеты "окна" могли поместиться в очереди. Стандартного размера очереди (50 пакетов) хватает для одновременной работы примерно 10 TCP-соединений (это число очень сильно зависит от настроек протокола TCP на машинах клиентов и на серверах, а так-же от среднего размера пакета, генерируемого приложениями). При превышении этот числа пакеты начнут теряться, что потребует их перепосылки заново. Если Вы платите за трафик - эта особенность может больно ударить Вас по карману: Ваш провайдер посчитает все переданные Вашей системе пакеты, в том числе и потерянные в dummynet, однако Вы (или Ваш клиент), получат только часть из них - поэтому, если Вы пускаете через один канал dummynet большое количество соединений - пропорционально увеличивайте и размер очереди. Причем подсчет пикового количества одновременных соединений вовсе не так прост - пользователи с зажатой пропускной способностью канала имеют обыкновение открывать гораздо больше одновременных соединений, чем обладатели высокоскоростных каналов: пока читают одну страницу - запускают на скачивание еще несколько. Кроме того, пользователи менеджеров загрузки типа GetRight быстро обнаружат, что закачка файла в несколько потоков происходит быстрее, чем в один - адресованные им пакеты, в виду большего их числа, будет "вытеснять" из очереди чужие соединения... да и продолжительность одного соединения возрастет, что тоже приведет к увеличению их одновременного числа.
Ну ладно, попугали - и хватит. Решением этих проблем может быть как ограничение числа соединений через pipe, так и грамотная настройка всей системы ограничения, в частности с использованием приоритетов трафика: каждый канал может иметь и больше одной очереди пакетов, при этом пакеты из очередей "выходят" в соответствии с приоритетами, заданными очередям. Для конфигурирования очереди используйте команду:
/sbin/ipfw queue <номер_очереди> config pipe <номер_канала> weight <вес>
, где <номер_очереди> - произвольно выбранный администратором идентификатор из диапазона 1-65534
<номер_канала> - номер канала, частью которого становится эта очередь
<вес> - приоритет очереди, число из диапазона 1-100, где 100 - самый приоритетный канал, 1 - самый бесправный. По умолчанию для каждой очереди устанавливается приоритет 1.
Чтобы "пропустить" трафик через канал, воспользуйтесь командами:
/sbin/ipfw add pipe <номер> <правило> или
/sbin/ipfw add quqeue <номер> <правило>, например
/sbin/ipfw add pipe 1 ip from any to 192.168.0.2 загонит в канал номер 1 весь трафик, идущий к пользователю 192.168.0.2.
Если нужно выставить одинаковые ограничения для большого количества пользователей, то вводить сотни правил, отличающихся только одним адресом может оказаться весьма утомительным занятием. Для упрощения таких задач FreeBSD предлагает дополнительный параметр mask, позволяющий сгруппировать абонентов на основе их IP-адресов: адрес комбинируется (не исключающее побитовое ИЛИ) с маской, и получившееся в результате значение является идентификатором группы, например
/sbin/ipfw add pipe 1 ip from any to 192.168.0.1/24 |
Создаст отдельные каналы для "четных" и "нечетных" адресов, т.е. адреса 192.168.0.2 и 192.168.0.4 будут делить один канал 64 кбит, а адреса 192.168.0.3 и 192.168.0.5 - другой
/sbin/ipfw add 100 pipe 1 ip from anu to 192.168.0.1/24 |
объединит отнесет в одну группу адреса с нулевым пятым битом (192.168.0.2 - 192.168.0.15, 192.168.0.32 - 192.168.0.47), а адреса с единичным пятым битом (192.168.0.16-192.168.0.31, 192.168.0.48-192.168.0.64) в другую.
указание маски 0x00000000 создаст собственный канал для каждого IP-адреса.
При указании маски в параметрах канала для каждой группы будет создан отдельный канал с теми же настройками пропускной способности, что и базовый, т.е. для первого рассмотренного случая (с маской 0x00000001) суммарная пропускная способность для пользователей будет равной 128 килобитам. При указании маски в параметрах очереди для каждой группы адресов будет создана очередь с тем же приоритетом (весом), что и базовая очередь, но все эти очереди попадут в один и тот-же канал, т.е. суммарная пропускная способность канала не изменится.
Если ограничение пропускной способности для каждого конкретного пользователя - не самоцель, а только средство "справедливо" разделить между ними имеющийся канал, то более корректной будет работа с одним каналом и несколькими очередями (возможно, с различным приоритетом), например:
/sbin/ipfw pipe 1 config bw 1000Kbit/s |
справедливо разделит пропускную способность в 1 мегабит между всеми пользователями сети, т.к. очереди равноприоритетны (пакеты будут выходить из пользовательских очередей "по очереди")
/sbin/ipfw pipe 1 config bw 1000Kbit/s |
даст некоторый приоритет в использовании канала пользователям с адресами, большими 192.168.0.128. Это неплохой инструмент для VIP-обслуживания некоторых абонентов сети без "глобального" ущемления прав рядовых пользователей: если никому из VIP-группы в данный момент канал не нужен, то обычные пользователи делят между собой пропускную способность поровну, но если VIP-абоненту понадобились услуги - простые пользователи автоматически подвигаются ...(процент за использование идеи можно присылать мне - о способе передачи договоримся :) ладно, шучу - пользуйтесь за так) Аналогичным образом можно, например, дать приоритет использования канала любителям поиграть через Интернет (отправив через привилегированную очередь пакеты с известных игровых серверов) за счет "качальщиков".
Если вышеприведенных сведений Вам не хватает - обратитесь к man ipfw. Там Вы сможете узнать о более тонкой настройке firewall, а так-же изучить возможности грядущей системы IPFIREWALL 2, позволяющий боле гибко строить правила и работать с дополнительной информацией о пакетах, такой как MAC-адреса пользователей и т.д.
Дополнительная настройка поведения системы
Далеко не все параметры поведения системы можно задать в файле конфигурации ядра при сборке - иначе файл вырос бы до неимоверных размеров, а система потеряла бы гибкость. Кроме того, малейшее изменение в поведении операционной системы потребовало бы перекомпиляции ядра и перезапуска системы, что не всегда удобно.
Для тонкой настройки поведения отдельных подсистем ядра используется утилита sysctl, позволяющая задать значение некоторый переменных ядра. Формат вызова утилиты sysctl следующий:
sysctl [опции] [имя переменной[=значение]] [...]
где имя переменной - имя переменной в объектной нотации вида подсистема.[подсистема...].переменная
=значение - устанавливаемое для переменной значение. Может быть строкой или числом. Не для каждой переменной можно установить значение, например для переменной kern.ostype, содержащей тип операционной системы, значение изменить нельзя (не поменяется же у Вас операционная система "на ходу"), а для kern.hostname, содержащей сетевое имя Вашего компьютера, значение установить можно.
опции - набор опций, изменяющих поведение утилиты sysctl. Вот самые, на мой взгляд, интересные:
-a - вывести вписок всех имеющихся переменных и их значений
-N - выводить только имена переменных
-n - выводить только значения переменных, например для помещения значения переменной ядра в переменную окружения (set kbootfile=`sysctl -n hw.physmem` для помещения в переменную окружения объема установленной в системе оперативной памяти)
-e - выводить переменный в формате имя=значение. Позволяет сохранить текущее состояние в файле (sysctl -ae > current.sysctl) перед изменением большого количества переменных, чтобы потом легко "скормить" их обратно (sysctl `cat current.sysctl`).
С полным списком доступных переменных Вы можете ознакомиться, посмотрев man sysctl, или введя команду sysctl -a, а мы рассмотрим только имеющее непосредственное отношение к настройке firewall.
net.inet.ip.fw.enable - логическая (булева) переменная (значения 0 и 1). Показывает, включено ли использование firewall в текущий момент. Позволяет включать и выключать firewall в любой момент времени.
net.inet.ip.fw.autoinc_step - целочисленная переменная. Задает шаг автоматического приращения номеров правил firewall при вводе без принудительного указания номера
net.inet.ip.fw.verbose и net.inet.ip.fw.verbose_limit - аналогичны соответствующим опциям ядра
net.inet.ip.fw.one_pass - логическая переменная. При ее установки в 0 пакет, выходящий из dummynet, продолжит свое путешествие по правилам firewall. В противном случае pipe действует, как allow. Значение по умолчанию - 1.
net.inet.ip.dummynet.hash_size - целочисленная переменная. Соответствует размеру хэш-таблицы, используемой dummynet для хранения очередей. Увеличение этого значение ускоряет работу dummynet при большом количестве очередей, естественно в обмен на оперативную память. Значение по умолчанию - 64.
net.inet.ip.dummynet.expire - логическая переменная. При установке в 1 очереди dummynet удаляются через некоторое время после того, как через них перестали "бегать" пакеты. В противном случае очереди удаляются только при нехватке памяти для размещения новых. Значение по умолчанию - 1. Имеет смысл выставлять в 0, если Ваш сервер обслуживает несколько крупных потребителей трафика, постоянно находящихся в режиме on-line - в этом случае кратковременное прекращение активности потребителя не должно вызывать удаления его очереди, чтобы не тратить времени на ее создание заново при появлении потребителя. В случае множества мелких потребителей, подключающихся и отключающихся от сети на длительный срок имеет смысл освобождать ресурсы, чтобы ускорить работу dummynet за счет меньшей таблицы очередей.
net.inet.ip.dummynet.max_chain_len - целочисленная переменная, значение по умолчанию - 16. Количество очередей, способных одновременно храниться в одной ячейке хэш-таблицы. При превышении этого значение пустые очереди удаляются. (или те, которым меньше всего повезло).
net.inet.ip.fw.dyn_keepalive - булева переменная. Заставляет генерировать "поддерживающие" пакеты (keep-alive) для tcp-соединений, обрабатываемых динамическими правилами keep-state. Установка в 1 понижает вероятность прерывания tcp-соединения по таймауту, но генерирует лишний трафик. Значение по умолчанию - 1
net.inet.ip.fw.dyn_max - целочисленная переменная. Максимальное количество одновременно существующих динамических правил. Значение по умолчанию - 8192.
О назначении других переменных Вы можете узнать в man ipfw.
Полагаю, что приведенной информации достаточно для создания достаточно продвинутой системы. К сожалению, в рамках одной статьи невозможно описать все аспекты и тонкости настройки сетевой подсистемы FreeBSD - поэтому при создании действительно сложных наборов правил на хорошо нагруженных серверах Вас могут ждать подводные камни, но, надеюсь, вы всегда сможете их решить при помощи справочной системы FreeBSD или при помощи специалистов.