Маршрутизатор на базе FreeBSD с приоритизацией трафика средствами PF и ALTQ
Проблема приоритизации трафика, на мой взгляд, весьма актуальна.
Интернет-канала много не бывает и на всех пользователей и сервисов локальной зачастую не хватает. Поэтому для нормальной работы Интернета требуется грамотное распределения полосы с учетом потребностей каждого из участников. Единственный раз, когда мне не понадобился QoS - это гарантированный провайдером канал в 20 Мбит/с в мир и 100Мбит/с - национальный. Но такое удовольствие не из дешевых, поэтому зачастую народ довольствуется ADSL-каналом с заявленной скоростью к клиенту до 5-10 Мбит/с. Хочу заметить, что данная статья не предназначенная для новичков в сетевом администрировании в целом и в PF в частности. Читателю необходимо иметь минимальные навыки работы с сетями (понимать устройство пакета, знать что такое ТСР-флаги и т.д.), а также с пакетным фильтром PF. Не лишним будет прочесть официальный FAQ и man'ы. В основном цель этой статьи поделиться опытом, выслушать замечания и, возможно, улучшить свой вариант. И так, постановка задачи: организовать доступ к сети Интернет. Грамотно распределить как входящий так и исходящий трафик с разделением канала для клиентов локальной сети и сервисов, запущенных на самом роутере (например, FTP-сервер, SIP-сервер и т.д.). В качестве роутера выступает сервер с ОС FreeBSD 9 c пакетным фильтром PF. Протокол FTP будет использоваться только в пассивном режиме, что немного упростит конфигурацию. Для решения поставленной задачи необходимо пересобрать ядро и включить в него поддержку PF и ALTQ. Для задач, не требующих ALTQ, пересобирать ядро не обязательно. Можно просто подгрузить PF как модуль. Добавляем в файл конфигурации следующие строки и пересобираем ядро. Описывать каждую опцию не буду. В man 4 altq все есть.
Лично я для боевого сервера пересобираю не только ядро системы, но и мир. Как это сделать, хорошо описано в Хендбуке и /usr/src/Makefile. Для автоматического запуска PF при старте системы добавляем в /etc/rc.conf строки:
Далее, собственно, сам конфигурационный файл пакетного фильтра. Возьмем самую простую реализацию роутера: один внутренний сетевой интерфейс и один внешний. Интернет канал подключен через ADSL-модем, работающий в режиме моста, т.е. подключение pppoe организовано средствами штатного ppp-клиента. Скорость от провайдера - 5 Мбит/c, к провайдеру - 850 Кбит/c. На роутере запущен HTTP-прокси для прозрачного перенаправления WWW-трафика пользователей сети. Это сделано с целью блокировать метод CONNECT и принудительно направить другие виды трафика (например, торрент) в другие очереди с другим приоритетом. Я использую легковесный, но "шустрый" 3proxy (3proxy.ru). Кому важен кэш - используйте Squid или Apache Traffic Server. Также перенаправляются все ДНС-запросы на сервер ДНС-провайдера. Это сделано с целью блокировки фишинговых и других зловредных сайтов, сайтов для взрослых, аплоадеры, соц. сети и т.д. и т.п. Некоторые компании так же предоставляет блокировку рекламных баннеров. Весь исходящий трафик я разбил на следующие очереди: - ДНС-запросы - очередь u_dns - ТСР АСК-пакеты - очередь u_ack - трафик с высоким приоритетом - очередь u_hipri - трафик с нормальным приоритетом - очередь u_pri - трафик с низким приоритетом - очередь u_lowpri - весь остальной трафик - очередь u_other - стандартная очередь - очередь u_std, одна очередь должна быть с опцией default, в которую попадает трафик, который не попадает ни под какое другое правило. В нашем случае это показатель правильности назначения очередей в правилах фильтрации. В эту очередь ничего не должно попадать. Аналогичное деление трафика, идущего к клиенту локальной сети, только вместо u_* используется d_* обозначение. Трафик классифицируется как относительно сервиса/протокола (HTTP, FTP, Torrent) так и относительно пользователя, т.е. трафик от/к компьютера, например, бухгалтера может быть весь помечен как с высоким приоритетом, независимо от того Торрент это или FTP. Данные, являющиеся ДНС-запросам и ТСР АСК-пакетами, для всех пользователей имеют свой высокий неизменный приоритет. Например, весь трафик от/к компьютера, относящегося к группе с низким приоритетом, будет обрабатываться с низким приоритетом, кроме ДНС и ТСР АСК. Определяем макросы, что бы меньше текста в основной части конфигурационного файла.
Таблица, в которую включены компьютеры трафик к/от которых весь будет считаться с высоким приоритетом.
Аналогично для ПК с нормальным приоритетом.
Таблица с адресами, доступ к которым блокируется.
Таблица, с адресами клиентов, которым можно доверять.
IP-адрес системного администратора.
IP-адреса SIP-провайдеров
Конфигурируем опции пакетного фильтра, изменяющие его поведение. В нашем случае: - не производится проверка на интерфейсе обратной петли; - выставляем оптимизацию правил в basic; - устанавливаем привязку состояний соединения (т.н. стейтов) к каждому интерфейсу; - устанавливаем максимальное кол-во состояний. Если сетевых интерфейсов большое кол-во или большое кол-во клиентов в сети, возможно, потребуется скорректировать это значение в большую сторону.
Нормализация трафика (т.н. скрабинг). Срабинг позволяет значительно повысить безопасность файервола. В нашем случае выполняется нормализация трафика на внешнем интерфейсе, генерируется случайная последовательность в поле идентификации IP-пакета, устанавливается величина TTL=128, производится "дефрагментация" IP-пакетов, а также нормализация TCP соединений.
ALTQ. Приоритизировать будем на всех физических сетевых интерфейсах. На внешнем - исходящий трафик, на внутреннем - входящий. Выбор дисциплины - очень важный момент. Возможные варианты: priq, cbq, hfsc. Я использую hfsc, т.к. важной чертой этого планировщика есть именно гарантирование полосы для конкретного пользователя/сервиса. Работа планировщика для нашего конкретного случая построена следующим образом: если в описании очереди указан дополнительный параметр realtime, то ей будет отдана указанная (realtime) полоса независимо ни от чего. Величина трафика свыше realtime будет рассчитываться исходя из величины bandwidth. Причем bandwidth - не абсолютный параметр, скорее относительный. Исходя из величин bandwidth каждой очереди рассчитывается величина трафика свыше realtime для каждой очереди пока не будет достигнут параметр upperlimit, который жестко ограничивает полосу. Приоритеты в планировщике hfsc не используются. Помимо всех прочих параметров, hfsc имеет параметр qlimit - кол-во слотов, доступных очереди для сохранения исходящих пакетов, когда вся доступная полоса исчерпана. И только когда все слоты будут заняты, пакеты будут отбрасываться, что заставит клиента снижать скорость. Мы не будем использовать RED или ECN, вместо этого увеличим значение qlimit. Назначаем очередь на внешнем интерфейсе. Величина bandwidth должна быть 96% от предоставляемой вышестоящим роутером. Здесь же перечисляем все дочерние очереди.
Очередь по-умолчанию. Будет потреблять 25 кбит/с независимо ни от чего. Величина bandwidth 1Kb означает, что если канал будет полностью занят любой другой очередью или всеми, то очередь u_std практически ничего не получит свыше 25 кбит/с.
Очередь u_ack - это ТСР АСК-пакеты, которые будут отправляться удаленному хосту с которого происходит загрузка по протоколу ТСР. Важно, что бы эти пакеты проходили без задержек. Для максимальной скорости от провайдера 4 Мбит/с требуется гарантированный канал в обратную сторону в размере 125 кбит/с.
ДНС-запросы. Гарантированной полосы в 25 кбит/с вполне достаточно. Больше не нужно, поэтому bandwidth 1Kb
Очередь с высоким приоритетом
Очередь с обычным приоритетом
Очередь с низким приоритетом
Очередь для всего остального трафика ТСР и UDP.
Назначаем очереди на внутреннем интерфейсе - приоритизируем входящий трафик. Провайдер отдает 5 Мбит/с, поэтому устанавливаем очередь inetq в размере 96%. Так же на внутреннем интерфейсе запущен ряд служб, например, локальный FTP, поэтому важно "не смешать" локальный трафик с Интернет-трафиком. Так как сетевая карточка 100Mbit, то выставляем значение bandwidth в 100Mb. Назначаем две очереди: одна - локальный трафик, вторая Интернет-трафик с дочерними очередями.
Очередь для локального трафика. В эту очередь будут попадать все пакеты, идущие от внутреннего сетевого интерфейса к пользователям локальной сети. Параметр upperlimit определяет максимальное значения для данной очереди. Заметьте, в эту очередь не будут попадать ответы, например, от WWW-сервера из сети Интернет. Эта очередь исключительно для локального трафика.
Очередь для Интернет-трафика. В эту очередь будут попадать пакеты, идущие с сети Интернет. Имеет дочерние очереди по аналогии с внешним интерфейсом.
Правила трансляции локальных адресов (NAT). Транслируются адреса, где источник - IP-адрес из любой подсети внутреннего интерфейса, а адрес назначения - любой, кроме IP-адресов из всех подсетей, подключенных к роутеру. Это могут быть как физические так и VPN-интерфейсы (tun, gif). ($ext_if) - в круглых скобках, т.к. IP-адрес внешнего интерфейса назначается динамически. ($int_if:network) и (self) в круглых скобках что бы в выводе pfctl -sn не было подстановки реальных адресов и сетей. Это удобно, когда у вас на внутреннем интерфейсе несколько алиасов и, соответственно, подсетей (как в моем случае).
Пользователей из группы pc_hipri и pc_pri пускаем в обход прокси. Я пускаю их напрямую, т.к. эти пользователи не нуждаются в контроле, а также специфическое ПО не работает в режиме прозрачного проксирования.
Правило редиректа, перенаправляющие все ДНС-запросы локальных пользователей на внешний ДНС-сервер. Это может быть Google или, лучше, ДНС-сервер компании, предоставляющей фильтрацию трафика посредством ДНС.
Редирект на прокси-сервер.
Редирект на удаленный рабочий стол виндовой машины в локальной сети из сети Интернет.
Правила фильтрации трафика. Правила будем группировать в такой последовательности: действие, интерфейс, направление, протокол, адрес источника, порт источника, адрес назначения, порт назначения. Антиспуфинг.
Блокируем не маршрутизируемые адреса.
Блокируем броадкасты.
Блокируем IP-адреса, содержащиеся в таблице ban. Опция return возвращает TCP RST, что закрывает сразу соединение без таймаута. Полезно, когда блокируются адреса рекламных сетей, что позволяет браузеру нормально загружать странички без ожидания загрузки блокируемого контента.
Эти 2 правила определяют тип файервола: запрещено все, кроме явно разрешенного.
Собственно разрешающие правила. Расположены в определенной последовательности, что важно с точки зрения производительности, а также ожидаемого эффекта. Внутренний интерфейс. Разрешаем ТСР-пакеты к интерфейсу обратной петли, на котором "слушает" прокси-сервер для организации прозрачного проксирования. Назначаем очереди. Мы не можем приоритизировать входящий трафик, только исходящий. В d_pri будут попадать пакеты, которые являются ответом от сервера к клиенту, таким образом мы регулируем скорость скачивания.
Далее 3 правила, которые разрешают ТСР соединения на определенные порты на не локальные IP-адреса. Назначаются соответствующие очереди. Тегирование необходимо что бы потом на внешнем интерфейсе мы могли "отделить" его от остального трафика и направить в нужную очередь. Заметьте, опция quick не используется, поэтому эти правила нужно расположить в правильной последовательности: от менее ограничивающего к более, потому как без опции quick последнее совпавшее правило выигрывает, а не первое совпавшее. Опция quick не используется т.к. при совпадении пакет будет назначен в очередь и пропущен и не дойдет до тех правил, которые описывают разрешения и приоритеты, основанные не на протоколах, а на адресах источника/назначения (в нашем случае это компьютеры из группы pc_hipri и pc_pri). Т.к. протокол ТСР, то так же добавляем очередь для ТСР АСК-пакетов. В качестве адреса назначения в правилах фигурирует !(self:network). Это значит, что только пакеты, не предназначенные ни к одному IP-адресу сетевых интерфейсов или IP-адресу из подсетей, подключенных к роутеру, будут разрешаться и, соответственно, тегироваться. Это, например, не даст подключиться к внешнему IP из локальной сети.
Далее 2 правила, которые будут срабатывать как для всех пользователей так и для тех, кто принадлежит к т.н. VIP-группе (pc_hipri и pc_pri). Поэтому тут используем опцию quick.
Следующие 2 правила, по-аналогии с TCP, описывают разрешения и очереди для протокола UDP. Так же их тегируем. Второе правило с опцией quick, т.к. оно должно срабатывать для всех категорий пользователей.
Правило, разрешающее ICMP.
Следующие правила, разрешающие трафик от клиентов, с высоким и нормальным приоритетом. Весь трафик будет считаться очень высоким (hipri) или высоким (pri) приоритетом (кроме ДНС и ТСР АСК). Здесь мы не указываем протокол, но указываем modulate state, который применяется только для ТСР. Это не будет ошибкой, PF достаточно "умный" и он подставит modulate state для протокола ТСР, и keep state - для всех остальных протоколов.
Разрешаем локальный Ethernet к внутреннему интерфейсу роутера.
Теперь опишем разрешающие правила с внутреннего интерфейса роутера в локальную сеть. Если у вас нет редиректа с Интернета в локальную сеть или нет никаких серверов/клиентов, запущенных на самом роутере и требующих доступ в локальную сеть, то эти правила можно не добавлять. Первое правило разрешает трафик с Интернета к указанному IP в локальной сети и назначает очень высокий приоритет входящего трафика. Это третье правило (первое - rdr, второе - разрешающее на внешнем интерфейсе) для редиректа (проброса) порта в локальную сеть.
Правило, разрешающее трафик от внутреннего сетевого интерфейса роутера в локальную сеть. Не важно какой протокол. Весь направляется в очередь etherq.
Внешний интерфейс. Разрешающие правила для входящего трафика. Важно, для каждого входящего правило указывать максимальное кол-во стейтов, которые может создать правило. Это предотвратит исчерпывания всего лимита стейтов одним правилом в случае DoS атаки. Последующие 6 правил разрешают входящие ТСР-подключения к определенным портам роутера, а также назначаются соответствующие очереди. Эти очереди будут приоритизировать не входящий трафик, а исходящий. Так же стоит обратить внимание на первые два правила, которые разрешают доступ к FTP серверу на роутере. Передача команд по 21-му порту будет направляться в очередь с большим приоритетом (u_pri), а данные - с меньшим (u_lowpri).
Правило, разрешающее входящее подключение с сети Интернет (конкретно с адреса администратора), но не к интерфейсам роутера (внешнему в том числе), а к компьютеру в локальной сети к порту RDP.
Следующее правило разрешает подключение с любого адреса сети Интернет к VNC-репитеру. В целях безопасности включен трекинг источника (source-track).
Следующие 2 правила разрешают подключения к определенным портам по протоколу UDP.
Разрешаем пинг к внешнему интерфейсу.
Внешний интерфейс. Разрешающие правила для исходящего трафика. Следующие 5 правил разрешают исходящий трафик с внешнего интерфейса, который был помечен на внутреннем интерфейсе. Это исключительно данные, которые передаются в сеть Интернет от клиентов в локальной сети.
И последние правила, разрешающие исходящие соединения с внешнего интерфейса. Это будет трафик непосредственно самого роутера. В целом приоритет этого трафика выше чем от клиентов в локальной сети.
Есть один важный момент, на котором остановлюсь подробнее. Второе правило будет разрешать ТСР-соединения с роутера и в том числе на 80 порт. Под это правило так же подпадают пакеты, отправленные с прокси-сервера, трафик, который фактически является HTTP-трафиком клиентов из локальной сети. Т.к. в нашем случае приоритеты этих видов трафика равны (очередь u_pri), то все хорошо. Но если планируется назначить очереди разные (например, HTTP от локальных клиентов - очередь u_lowpri, а с внешнего интерфейса роутера - u_pri), тогда следует указать в правиле для прокси-сервера опцию user uid и поместить его над правилом для внешнего интерфейса роутера. Например, прокси запущен с правами пользователя nobody:
Соответственно, правило, разрешающее доступ к прокси из локальной сети тоже немного измениться: необходимо поменять очередь с d_pri на d_lowpri.
Стоить отметить о наличии бага, который проявляется при использованием опции user. Об этом описано в секции BUGS на странице руководства pf.conf. Лично у меня этот баг не проявлялся. Все же старайтесь опцию user не использовать. Отладка. Отличительной способностью PF есть его протоколирование, статистика и мониторинг состояния в реальном времени что значительно облегчает конфигурирование файервола, особенно для сложных сетевых топологий. Просмотр загруженных очередей:
Что бы в реальном времени наблюдать загрузку очередей выполните команду:
Так же рекомендую установить из портов программу pftop, которая по аналогии с утилитой top выводит различную статистику PF в реальном времени. Рейтинг статьи:
Нашли ошибку?
|
Уважаемый посетитель, Вы зашли на сайт как незарегистрированный пользователь. Мы рекомендуем Вам зарегистрироваться либо зайти на сайт под своим именем.