Электронная почта давно является основным способом обмена документами. Но после того, как я заменил во многих организациях в моем городе старые сименсы и панасы на Asterisk PBX, сталкивался с нежеланием отказываться от факсов(особенно в бюджетных организациях), и понятно — это быстрее и проще для сотрудника, чем возиться со сканером. Так как астер они ставили в основном вследствие расширения штата и с желанием сэкономить, то факсы для новых сотрудников необходимо также виртуализировать. С приемом факса на e-mail проблем возникнуть не должно, с простым и бесплатным способом отправки пришлось поломать голову.

На просторах интернета нашел простой способ отправки факса через веб-интерфейс FreePBX. Несложно настроить, работает на ура. Для активного использования факсов в крупном офисе вряд ли подойдет, но для небольшого офиса с небольшим факсовым трафиком или для новичков в астере или *nix — в самый раз.

Мы имеем виртуальную машина в небольшом офисе с Ubuntu 12.04 на борту. Установлен Asterisk 11 + FreePBX 2.11. Логинимся по ssh на сервер и приступаем.

1. Устанавливаем модуль факса. Также можно использовать модуль spandsp, в нем нет ограничений


Регистрируемся на сайте Digium, идем на  страницу модуля, жмем «Get 1 Free license» оформляем заказ, ждем письмо с кодом.
Отсюда скачиваем утилиту для регистрации нашего модуля, кладем в /tmp, отмечаем выполнение для владельца и запускаем.

cd /tmp
wget http://downloads.digium.com/pub/register/x86-32/register
chmod 500 register
./register


Вы увидите текстовое меню с приглашением для ввода:

Digium Product Registration - Version 3.0.5
Copyright (C) 2004-2007, Digium, Inc.
Use the '-l' option to see license information for software
included in this program.

Please select a category

1 - Digium Products
2 - Cepstral Products

0 - Quit
Your Choice:


Выбираем 1, затем 9, вводите ключ, который пришел на почту, соглашаетесь и заполняете данные.
Сам модуль берем тут, выбираем версию под свой сервер, забираем по ссылке внизу, распаковываем и кладем res_fax_digium.so в ваш ${ASTMODDIR}. Например, у меня

cd /tmp
wget http://downloads.digium.com/pub/telephony/fax/res_fax_digium/asterisk-11.0/x86-64/res_fax_digium-11.0_1.3.1-generic_64.tar.gz
tar -xvf res_fax_digium*
cd res_fax_digium*
cp res_fax_digium.so /usr/lib/asterisk/modules/

 

2. Скачаем нужные нам файлы и распакуем их во временный каталог.

 

cd /tmp && wget http://faxgui-ari-module.googlecode.com/files/faxgui-ari-module.tar.gz && tar xvf faxgui-ari-module.tar.gz

 

3. Копируем все на свои места и устаналиваем права.

 

cp faxgui-ari-module/sendfax.module /var/www/recordings/modules/ # проверьте ваш параметр %AMPROOT%
cp faxgui-ari-module/sendfaxnotify.php /var/lib/asterisk/bin/  # проверьте ваш параметр ${ASTVARLIBDIR}
chown asterisk:asterisk /var/www/recordings/modules/sendfax.module
chown asterisk:asterisk /var/lib/asterisk/bin/sendfaxnotify.php
dos2unix /var/lib/asterisk/bin/sendfaxnotify.php # перекодировка файла, установите пакет dos2unix

 

4. Создаем контекст для исходящих факсов в файле /etc/asterisk/extensions_custom.conf.

[outboundfax]
exten => s,1,Set(FAXOPT(filename)=${FAXFILE})
exten => s,n,Set(FAXOPT(ecm)=yes)
exten => s,n,Set(FAXOPT(headerinfo)=${FAXHEADER})
exten => s,n,Set(FAXOPT(localstationid)=${LOCALID})
exten => s,n,Set(FAXOPT(maxrate)=14400)
exten => s,n,Set(FAXOPT(minrate)=2400)
exten => s,n,SendFAX(${FAXFILE},d)
exten => s,n,System(${ASTVARLIBDIR}/bin/sendfaxnotify.php INIT "${EMAIL}" "${DESTINATION}" "${TIMESTAMP}" "NO_STATUS" "NO_PAGES")
exten => h,1,NoOp(FAXOPT(ecm) : ${FAXOPT(ecm)})
exten => h,n,NoOp(FaxStatus : ${FAXSTATUS})
exten => h,n,NoOp(FaxStatusString : ${FAXSTATUSSTRING})
exten => h,n,NoOp(FaxError : ${FAXERROR})
exten => h,n,NoOp(RemoteStationID : ${REMOTESTATIONID})
exten => h,n,NoOp(FaxPages : ${FAXPAGES})
exten => h,n,NoOp(FaxBitRate : ${FAXBITRATE})
exten => h,n,NoOp(FaxResolution : ${FAXRESOLUTION})
exten => h,n,System(${ASTVARLIBDIR}/bin/sendfaxnotify.php NOTIFY "${EMAIL}" "${DESTINATION}" "${TIMESTAMP}" "${FAXSTATUSSTRING}" "${FAXPAGES}")
; end of outboundfax context

 

5. Перезапуск и проверка.

 

amportal restart


Идем в User Panel нашего сервера, ip_aster/recordings/, входим под любым пользователем, вводим пароль от голосовой почты. Слева появился пункт Send Fax. Проверяем отправку.

Для удобства и скорости обучения пользователей я отметил алгоритм отправки цифрами, так намного понятнее.

Вот и все, надеюсь, мой пост помог кому-либо с настройкой VoIP-сервера.
В будущем планирую регулярно описывать такие небольшие и тонкие моменты с настройкой.

При написании статьи были использованы материалы:

hiousi.tumblr.com/post/2745684940/a-freepbx-ari-module-to-send-fax-from-the-user-portal
trentdev.blogspot.ru/2013/04/send-fax-using-asteriskfreepbx-with.html
www.digium.com/en/products/software/fax-for-asterisk
wiki.freepbx.org/display/ST/Faxing+and+T38

Небольшое дополнение
Сейчас настраивал отправку клиенту по своему мануалу, вспомнил еще несколько моментов.

1. Для поддежки PDF установите пакет ghostscript

aptitude install ghostscript # мой случай

2. Не забудьте про опции в sip.conf, либо в веб-интерфейсе

t38pt_udptl=yes,redundancy,maxdatagram=400
faxdetect=no

3. При проверке посмотрите лицензию в CLI

fax show licenses

Не регистрируйте несколько ключей на 1 ящик, чревато дальнейшей невалидностью

* «sysctl -w net.inet.tcp.msl=7500» — время ожидания ACK в ответ на SYN-ACK или
FIN-ACK в миллисекундах;
* «sysctl -w net.inet.tcp.blackhole=2» — все пакеты на закрытый порт
отбрасываются без отсылки RST;
* «sysctl -w net.inet.udp.blackhole=1» — отбрасывать пакеты для закрытых портов;
* «sysctl -w net.inet.icmp.icmplim=50» — защита от генерирование потока ответных пакетов, 
максимальное количество ICMP Unreachable и TCP RST пакетов в секунду;
* «sysctl -w kern.ipc.somaxconn=32768» — увеличение числа одновременно открытых сокетов;
* Сборка ядра с опцией DEVICE_POLLING (далее: sysctl kern.polling.enable=1;
sysctl kern.polling.user_frac=50);

Предисловие

В новых дистрибутивах Линукс стало модным называть разделы не по «именам», скажем, /dev/hda2, а используя UUID'ы — Уникальные Идентификаторы. Выглядят они как абсолютно нечитаемые для человека многозначные номера, да еще и шестнадцатеричные, например: UUID="5a179614-0415-48c6-a9ad-3f6ad9596619".

Удобство понимания и заполнения таких конфигурационных файлов как, скажем, /etc/fstab «значительно повысилось». Стало невозможным понять о каком разделе идет речь. Хорошо если у вас всего пять-шесть разделов, еще можно помнить, на каком своп, а на каком корень. А если разделов в три раза больше? Да если еще и постоянно удаляешь одни, и создаешь другие? Мода требует жертв.

Кому же нужны UUID'ы и для кого они действительно удобны? Сисадминам больших серверов, у которых одновременно присутствуют носители всевозможных типов, да еще и объединенные во всякие RAID'ы и прочие сиадминские заморочки. Для них, когда возникает необходимость перенести содержимое с одного носителя на другой, потом встает большая проблема правильно внести изменения в ту же /etc/fstab вручную. С UUID'ами же ядро, при помощи специальных программ, автоматически находит и размечает разделы по соответствующим носителям. Это им экономит много сил и времени.

Простым же смертным, имеющим два компьютера с тремя винчестерами на обоих, эти UUID'ы нужны как зайцу стоп-сигнал. Я лично первым делом безжалостно удаляю все эти номера из файлов /etc/fstab и /boot/grub/menu.lst. Это позволяет мне избежать головной боли при клонировании разделов, когда возникают два раздела с одинаковыми «Уникальными номерами».

Но многим почему-то нравятся UUID'ы, и они озабочены, если какой-нибудь раздел, например подкачки, вдруг прописан по «имени-отчеству». В Сети иногда встречаются такие вопли о помощи: «Мой раздел своппига не имеет UUID'а. Как мне узнать его и вписать в /etc/fstab?». Для вас, любители UUID'ов, эта статья.

Команда blkid

Программа blkid, используя библиотеку libblkid, умеет читать содержимое файлов блочных устройств типа /dev/hda2. Эти специальные файлы, находящиеся в директории /dev иначе называются нодами устройств, имеют весьма специфичную структуру, и не могут быть прочитаны обычными средствами (скажем, командой cat).

Однако программа blkid по умолчанию не считывает информацию о разделах непосредственно из соответствующих нод устройств, а считывает ее из файла /etc/blkid.tab. Этот файл зачем-то называется в мане команды blkid кэш файлом, а всем известно, что слово cache имеет множесто значений, а потому совершенно бессмысленно. Должен вас сразу предупредить, что в файле /etc/blkid.tab со временем накапливается устаревшая информация о давно несуществующих разделах, поэтому не думайте читать сам файл в поисках UUID'ов, можете жестоко обмишулиться. Пользуйтесь командой blkid с соответсвующими опциями.

Команда blkid без опций

Команда blkid без опций, запущенная с правами суперпользоателя, выведет на экран дисплея информацию, содержащуюся в файле /etc/blkid.tab:

# blkid
/dev/disk/by-id/scsi-SATA_Hitachi_HTS5416_SB344CHRJT80JD-part7: UUID="465e53f5-a682-4fde-8e0c-4c77a533aca7" TYPE="ext3" SEC_TYPE="ext2" LABEL="Common"
/dev/sda2: UUID="02E4E3A0E4E39467" LABEL="Vista" TYPE="ntfs"
/dev/sda5: UUID="5a179614-0415-48c6-a9ad-3f6ad9596619" TYPE="ext3" SEC_TYPE="ext2"
/dev/sda6: TYPE="swap"
/dev/sda7: UUID="465e53f5-a682-4fde-8e0c-4c77a533aca7" TYPE="ext3" LABEL="Common"
/dev/disk/by-uuid/5a179614-0415-48c6-a9ad-3f6ad9596619: UUID="5a179614-0415-48c6-a9ad-3f6ad9596619" TYPE="ext3" SEC_TYPE="ext2"
/dev/sda8: UUID="41825dd5-d866-45f6-bcfd-c4c9aa4de045" SEC_TYPE="ext2" TYPE="ext3" LABEL="lenny"
/dev/sda9: UUID="e6758566-4e3b-4cf0-be5e-37949b52c64f" SEC_TYPE="ext2" TYPE="ext3" LABEL="deb2"
/dev/sda1: UUID="5408E10E08E0F042" LABEL="WinRE" TYPE="ntfs"

Я предупреждал. Тут, конечно, можно разобраться при желании, но непонятно, откуда может взяться такое желание, когда можно поступить проще. А именно запустить команду blkid с опцией -c.

Команда blkid с опцией -c

Вообще-то опция -c заставляет blkid читать не из файла blkid.tab, а из любого указанного файла. Скажем, /dev/null. Не имея никакой информации из данного файла, команда вынуждена будет прочитать информацию из нод устройств, то есть выдать нам реальную картину на текущий момент:

# blkid -c /dev/null
/dev/sda1: UUID="5408E10E08E0F042" LABEL="WinRE" TYPE="ntfs"
/dev/sda2: UUID="02E4E3A0E4E39467" LABEL="Vista" TYPE="ntfs"
/dev/sda5: UUID="5a179614-0415-48c6-a9ad-3f6ad9596619" TYPE="ext3"
/dev/sda6: TYPE="swap"
/dev/sda7: LABEL="Common" UUID="465e53f5-a682-4fde-8e0c-4c77a533aca7" TYPE="ext3"
/dev/sda8: LABEL="lenny" UUID="41825dd5-d866-45f6-bcfd-c4c9aa4de045" SEC_TYPE="ext2" TYPE="ext3"
/dev/sda9: LABEL="deb2" UUID="e6758566-4e3b-4cf0-be5e-37949b52c64f" SEC_TYPE="ext2" TYPE="ext3"

Совсем другое дело, не правда ли?

Поэтому советую сохранить старые файлы blkid.tab и blkid.tab.old под другими именами, тогда при следующей загрузке будет создан новенький чистенький файлик blkid.tab, где все будет как в выводе команды blkid -c /dev/null. Стоит после этого проверить /etc/fstab и /boot/grub/menu.lst.

Остальные опции команды крайне невыразительны и бесполезны. Чем трудиться запоминать их, проще запустить команду вовсе без опций или с опцией -c /dev/null. Тем не менее:

Опция <device>

# blkid /dev/sda5
/dev/sda5: UUID="5a179614-0415-48c6-a9ad-3f6ad9596619" TYPE="ext3" SEC_TYPE="ext2"

Выдает сведения об указанном устройстве.

Опция -t

# blkid -t TYPE=ntfs
/dev/sda2: UUID="02E4E3A0E4E39467" LABEL="Vista" TYPE="ntfs"
/dev/sda1: UUID="5408E10E08E0F042" LABEL="WinRE" TYPE="ntfs"

Найдет все устройства, отвечающие заданному критерию, будь то TYPE, LABEL, или UUID. Можно сужать круг поиска, вводя в командную строку имена интересующих устройств:

# blkid -t TYPE=ntfs /dev/sda1 /dev/sda2 /dev/sda6 /dev/sda7
/dev/sda1: UUID="5408E10E08E0F042" LABEL="WinRE" TYPE="ntfs"
/dev/sda2: UUID="02E4E3A0E4E39467" LABEL="Vista" TYPE="ntfs"

Опция -s

# blkid -s UUID /dev/sda7
/dev/sda7: UUID="465e53f5-a682-4fde-8e0c-4c77a533aca7"

Выдаст только указанный критерий нужного устройства.

Опция -o

Позволяет выбирать формат вывода из трех возможных: value (значение критерия), device (устройство), или full (полный). Например:

# blkid -o value
465e53f5-a682-4fde-8e0c-4c77a533aca7
ext3
ext2
Common
02E4E3A0E4E39467
Vista
ntfs
5a179614-0415-48c6-a9ad-3f6ad9596619
ext3
ext2
swap
465e53f5-a682-4fde-8e0c-4c77a533aca7
ext3
Common
5a179614-0415-48c6-a9ad-3f6ad9596619
ext3
ext2
41825dd5-d866-45f6-bcfd-c4c9aa4de045
ext2
ext3
lenny
e6758566-4e3b-4cf0-be5e-37949b52c64f
ext2
ext3
deb2
5408E10E08E0F042
WinRE
ntfs

Опция -l

Применяется вместе с опцией поиска -t. Но из всего найденного выдаст сведения только об одном устройстве. Обычно это первое прочитанное в файле /etc/blkid.tab устройство.

# blkid -lt TYPE=ntfs
/dev/sda2: UUID="02E4E3A0E4E39467" LABEL="Vista" TYPE="ntfs"

Опция -g

В мане сказано, что убирает мусор в каком-то кэше blkid. Если имеется в виду файл /etc/blkid.tab, то не работает.

Опция -w

Записывает данные в указанный вами файл, вместо файла /etc/blkid.tab.

По моему, проще переадресовать в файл «file» вывод команды.

# blkid -c /dev/null > file

Опция -h

Выводит помощь.

Опция -v

Выводит версию программы.

Вот все, что касается команды blkid. Однако существуют и другие возможности узнать UUID раздела.

Самая очевидная — заглянуть в директорию /dev:

# ls /dev/disk
by-id  by-label  by-path  by-uuid

Там четыре субдиректории, одна из которых by-uuid. Посмотрим:

# ls /dev/disk/by-uuid
02E4E3A0E4E39467                      5408E10E08E0F042
41825dd5-d866-45f6-bcfd-c4c9aa4de045  5a179614-0415-48c6-a9ad-3f6ad9596619
465e53f5-a682-4fde-8e0c-4c77a533aca7  e6758566-4e3b-4cf0-be5e-37949b52c64f

Вот поди, догадайся, что к чему относится! Нет, это не метод.

Команда vol_id

Существует еще команда vol_id. Она настолько простая, и ман к ней так понятно написан, что разобраться с ней не составит труда. Например:

# vol_id /dev/sda2
ID_FS_USAGE=filesystem
ID_FS_TYPE=ntfs
ID_FS_VERSION=3.1
ID_FS_UUID=02E4E3A0E4E39467
ID_FS_UUID_ENC=02E4E3A0E4E39467
ID_FS_LABEL=Vista
ID_FS_LABEL_ENC=Vista
ID_FS_LABEL_SAFE=Vista

Или еще пример:

# vol_id --uuid /dev/sda5
5a179614-0415-48c6-a9ad-3f6ad9596619

Хорошая и удобная команда, жаль, что не во всех дистрибутивах встречается.

Заключение

На сладкое я приберег самое интересное: кто же присваивает устройствам UUID'ы? Где записаны эти самые идентификаторы?

Если говорить о разделах жесткого диска, то UUID'ы присваиваются им в процессе создания файловой системы (некоторые утверждают, что они вычисляются из характеристик раздела), и записываются где-нибудь в суперблоках. Во всяком случае, еще не отформатированный раздел не имеет UUID'а. А при клонировании раздела командой dd, раздел, в который устанавливают клон, меняет свой UUID на идентификатор клона.

При загрузке компьютера, программа udev записывает UUID раздела в его ноду — файл блочного устройства в директории /dev. В доступной пользователю части файловой системы, UUID'ы разделов можно найти в файле /etc/blkid.tab, но информация эта может оказаться устаревшей.

Нравится мне это или нет, но UUID'ы прочно вошли в повседневный быт линуксоида. И нет в них никакой мистики.

Проблема приоритизации трафика, на мой взгляд, весьма актуальна. 
Интернет-канала много не бывает и на всех пользователей и сервисов локальной зачастую не хватает. Поэтому для нормальной работы Интернета требуется грамотное распределения полосы с учетом потребностей каждого из участников. 
Единственный раз, когда мне не понадобился QoS — это гарантированный провайдером канал в 20 Мбит/с в мир и 100Мбит/с — национальный. Но такое удовольствие не из дешевых, поэтому зачастую народ довольствуется ADSL-каналом с заявленной скоростью к клиенту до 5-10 Мбит/с.

Хочу заметить, что данная статья не предназначенная для новичков в сетевом администрировании в целом и в PF в частности. Читателю необходимо иметь минимальные навыки работы с сетями (понимать устройство пакета, знать что такое ТСР-флаги и т.д.), а также с пакетным фильтром PF. Не лишним будет прочесть официальный FAQ и man'ы. В основном цель этой статьи поделиться опытом, выслушать замечания и, возможно, улучшить свой вариант.

И так, постановка задачи: организовать доступ к сети Интернет. Грамотно распределить как входящий так и исходящий трафик с разделением канала для клиентов локальной сети и сервисов, запущенных на самом роутере (например, FTP-сервер, SIP-сервер и т.д.). В качестве роутера выступает сервер с ОС FreeBSD 9 c пакетным фильтром PF.
Протокол FTP будет использоваться только в пассивном режиме, что немного упростит конфигурацию.

Для решения поставленной задачи необходимо пересобрать ядро и включить в него поддержку PF и ALTQ. Для задач, не требующих ALTQ, пересобирать ядро не обязательно. Можно просто подгрузить PF как модуль.

Добавляем в файл конфигурации следующие строки и пересобираем ядро. Описывать каждую опцию не буду. В man 4 altq все есть.

options HZ=<span class="number" style="color: #2aa198;">1000</span>
device pf
device pflog
options ALTQ
options ALTQ_CBQ
options ALTQ_RED
options ALTQ_RIO
options ALTQ_HFSC
options ALTQ_CDNR
options ALTQ_PRIQ
#options ALTQ_NOPCC #<span class="keyword" style="color: #859900;">for</span> SMP CPU



Лично я для боевого сервера пересобираю не только ядро системы, но и мир. Как это сделать, хорошо описано в Хендбуке и /usr/src/Makefile.

Для автоматического запуска PF при старте системы добавляем в /etc/rc.conf строки:

<span class="setting">pf_enable=<span class="value"><span class="string" style="color: #2aa198;">"YES"</span></span></span>
<span class="setting">pflog_enable=<span class="value"><span class="string" style="color: #2aa198;">"YES"</span></span></span>



Далее, собственно, сам конфигурационный файл пакетного фильтра. Возьмем самую простую реализацию роутера: один внутренний сетевой интерфейс и один внешний. Интернет канал подключен через 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.
Данные, являющиеся ДНС-запросам и ТСР АСК-пакетами, для всех пользователей имеют свой высокий неизменный приоритет. Например, весь трафик от/к компьютера, относящегося к группе с низким приоритетом, будет обрабатываться с низким приоритетом, кроме ДНС и ТСР АСК.

Определяем макросы, что бы меньше текста в основной части конфигурационного файла.

<span class="setting">mst=<span class="value"><span class="string" style="color: #2aa198;">"modulate state"</span></span></span>
<span class="setting">str=<span class="value"><span class="string" style="color: #2aa198;">"source-track rule"</span></span></span>
<span class="setting">ext_if=<span class="value"><span class="string" style="color: #2aa198;">"tun0"</span></span></span>
<span class="setting">int_if=<span class="value"><span class="string" style="color: #2aa198;">"rl0"</span></span></span>



Таблица, в которую включены компьютеры трафик к/от которых весь будет считаться с высоким приоритетом.

table <span class="tag"><<span class="title" style="font-weight: bold; color: #268bd2;">pc_hipri</span>></span> persist {10.11.1.2}



Аналогично для ПК с нормальным приоритетом.

table <span class="tag"><<span class="title" style="font-weight: bold; color: #268bd2;">pc_pri</span>></span> persist {10.13.1.2 10.13.1.10 10.13.1.13 10.13.1.14 10.13.1.15}



Таблица с адресами, доступ к которым блокируется.

table <span class="tag"><<span class="title" style="font-weight: bold; color: #268bd2;">ban</span>></span> persist file "/etc/pf.ban"



Таблица, с адресами клиентов, которым можно доверять.

table <span class="tag"><<span class="title" style="font-weight: bold; color: #268bd2;">trust</span>></span> persist {123.10.456.0/24 193.196.125.0/24}



IP-адрес системного администратора.

table <span class="tag"><<span class="title" style="font-weight: bold; color: #268bd2;">me</span>></span> persist {210.211.13.84}



IP-адреса SIP-провайдеров

table <span class="tag"><<span class="title" style="font-weight: bold; color: #268bd2;">sip_peers</span>></span> persist {212.15.65.122 75.16.127.118}



Конфигурируем опции пакетного фильтра, изменяющие его поведение. В нашем случае:

— не производится проверка на интерфейсе обратной петли;
— выставляем оптимизацию правил в basic;
— устанавливаем привязку состояний соединения (т.н. стейтов) к каждому интерфейсу;
— устанавливаем максимальное кол-во состояний. 

Если сетевых интерфейсов большое кол-во или большое кол-во клиентов в сети, возможно, потребуется скорректировать это значение в большую сторону.

<span class="operator"><span class="keyword" style="color: #859900;">set</span> skip <span class="keyword" style="color: #859900;">on</span> lo0
<span class="keyword" style="color: #859900;">set</span> ruleset-optimization basic
<span class="keyword" style="color: #859900;">set</span> state-policy if-bound
<span class="keyword" style="color: #859900;">set</span> limit states <span class="number" style="color: #2aa198;">20000</span></span>



Нормализация трафика (т.н. скрабинг). Срабинг позволяет значительно повысить безопасность файервола. В нашем случае выполняется нормализация трафика на внешнем интерфейсе, генерируется случайная последовательность в поле идентификации IP-пакета, устанавливается величина TTL=128, производится «дефрагментация» IP-пакетов, а также нормализация TCP соединений.

scrub on <span class="variable" style="color: #b58900;">$ext_if</span> all random-id <span class="keyword" style="color: #859900;">no</span>-df min-ttl <span class="number" style="color: #2aa198;">128</span> fragment reassemble reassemble tcp




ALTQ.

Приоритизировать будем на всех физических сетевых интерфейсах. На внешнем — исходящий трафик, на внутреннем — входящий. Выбор дисциплины — очень важный момент. Возможные варианты: priq, cbq, hfsc. 

Я использую hfsc, т.к. важной чертой этого планировщика есть именно гарантирование полосы для конкретного пользователя/сервиса. Работа планировщика для нашего конкретного случая построена следующим образом: если в описании очереди указан дополнительный параметр realtime, то ей будет отдана указанная (realtime) полоса независимо ни от чего. Величина трафика свыше realtime будет рассчитываться исходя из величины bandwidth. Причем bandwidth — не абсолютный параметр, скорее относительный.

Исходя из величин bandwidth каждой очереди рассчитывается величина трафика свыше realtime для каждой очереди пока не будет достигнут параметр upperlimit, который жестко ограничивает полосу. Приоритеты в планировщике hfsc не используются. 

Помимо всех прочих параметров, hfsc имеет параметр qlimit — кол-во слотов, доступных очереди для сохранения исходящих пакетов, когда вся доступная полоса исчерпана. И только когда все слоты будут заняты, пакеты будут отбрасываться, что заставит клиента снижать скорость. Мы не будем использовать RED или ECN, вместо этого увеличим значение qlimit.

Назначаем очередь на внешнем интерфейсе. Величина bandwidth должна быть 96% от предоставляемой вышестоящим роутером. Здесь же перечисляем все дочерние очереди. 

altq on <span class="variable" style="color: #b58900;">$ext_if</span> hfsc bandwidth <span class="number" style="color: #2aa198;">800</span>Kb queue {u_std,u_ack,u_dns,u_hipri,u_pri,u_lowpri,u_other}



Очередь по-умолчанию.
Будет потреблять 25 кбит/с независимо ни от чего. Величина bandwidth 1Kb означает, что если канал будет полностью занят любой другой очередью или всеми, то очередь u_std практически ничего не получит свыше 25 кбит/с.

queue u_std bandwidth <span class="number" style="color: #2aa198;">1</span>Kb qlimit <span class="number" style="color: #2aa198;">50</span> hfsc (<span class="keyword" style="color: #859900;">default</span> realtime <span class="number" style="color: #2aa198;">25</span>Kb)



Очередь u_ack — это ТСР АСК-пакеты, которые будут отправляться удаленному хосту с которого происходит загрузка по протоколу ТСР. Важно, что бы эти пакеты проходили без задержек. Для максимальной скорости от провайдера 4 Мбит/с требуется гарантированный канал в обратную сторону в размере 125 кбит/с.

queue u_ack bandwidth 1Kb qlimit 200 hfsc (realtime 125Kb)



ДНС-запросы. 
Гарантированной полосы в 25 кбит/с вполне достаточно. Больше не нужно, поэтому bandwidth 1Kb

queue u_dns bandwidth 1Kb qlimit 50 hfsc (realtime 25Kb)



Очередь с высоким приоритетом

queue u_hipri bandwidth 300Kb qlimit 250 hfsc (realtime 200Kb)



Очередь с обычным приоритетом

queue u_pri bandwidth 300Kb qlimit 400 hfsc (realtime 150Kb)



Очередь с низким приоритетом

queue u_lowpri bandwidth 100Kb qlimit 100 hfsc (realtime 75Kb)



Очередь для всего остального трафика ТСР и UDP.

queue u_other bandwidth 97Kb qlimit 50 hfsc (realtime 25Kb)



Назначаем очереди на внутреннем интерфейсе — приоритизируем входящий трафик. 

Провайдер отдает 5 Мбит/с, поэтому устанавливаем очередь inetq в размере 96%. Так же на внутреннем интерфейсе запущен ряд служб, например, локальный FTP, поэтому важно «не смешать» локальный трафик с Интернет-трафиком. Так как сетевая карточка 100Mbit, то выставляем значение bandwidth в 100Mb. Назначаем две очереди: одна — локальный трафик, вторая Интернет-трафик с дочерними очередями.

altq on <span class="variable" style="color: #b58900;">$int_if</span> hfsc bandwidth <span class="number" style="color: #2aa198;">100</span>Mb queue {etherq, inetq}



Очередь для локального трафика.
В эту очередь будут попадать все пакеты, идущие от внутреннего сетевого интерфейса к пользователям локальной сети. Параметр upperlimit определяет максимальное значения для данной очереди. Заметьте, в эту очередь не будут попадать ответы, например, от WWW-сервера из сети Интернет. Эта очередь исключительно для локального трафика.

queue etherq bandwidth 95Mb hfsc (upperlimit 95Mb)



Очередь для Интернет-трафика. 
В эту очередь будут попадать пакеты, идущие с сети Интернет. Имеет дочерние очереди по аналогии с внешним интерфейсом.

queue inetq bandwidth <span class="number" style="color: #2aa198;">4800</span>Kb hfsc (upperlimit <span class="number" style="color: #2aa198;">4800</span>Kb) {d_std,d_ack,d_dns,d_hipri,d_pri,d_lowpri,d_other}
queue d_std bandwidth <span class="number" style="color: #2aa198;">1</span>Kb qlimit <span class="number" style="color: #2aa198;">50</span> hfsc (<span class="keyword" style="color: #859900;">default</span> realtime <span class="number" style="color: #2aa198;">25</span>Kb)
queue d_ack bandwidth <span class="number" style="color: #2aa198;">1</span>Kb qlimit <span class="number" style="color: #2aa198;">50</span> hfsc (realtime <span class="number" style="color: #2aa198;">50</span>Kb)
queue d_dns bandwidth <span class="number" style="color: #2aa198;">1</span>Kb qlimit <span class="number" style="color: #2aa198;">50</span> hfsc (realtime <span class="number" style="color: #2aa198;">25</span>Kb)
queue d_hipri bandwidth <span class="number" style="color: #2aa198;">1297</span>Kb qlimit <span class="number" style="color: #2aa198;">500</span> hfsc (realtime <span class="number" style="color: #2aa198;">1000</span>Kb)
queue d_pri bandwidth <span class="number" style="color: #2aa198;">2000</span>Kb qlimit <span class="number" style="color: #2aa198;">500</span> hfsc (realtime <span class="number" style="color: #2aa198;">2000</span>Kb)
queue d_lowpri bandwidth <span class="number" style="color: #2aa198;">1000</span>Kb qlimit <span class="number" style="color: #2aa198;">500</span> hfsc (realtime <span class="number" style="color: #2aa198;">500</span>Kb)
queue d_other bandwidth <span class="number" style="color: #2aa198;">500</span>Kb qlimit <span class="number" style="color: #2aa198;">500</span> hfsc (realtime <span class="number" style="color: #2aa198;">240</span>Kb)



Правила трансляции локальных адресов (NAT).

Транслируются адреса, где источник — IP-адрес из любой подсети внутреннего интерфейса, а адрес назначения — любой, кроме IP-адресов из всех подсетей, подключенных к роутеру. Это могут быть как физические так и VPN-интерфейсы (tun, gif).
($ext_if) — в круглых скобках, т.к. IP-адрес внешнего интерфейса назначается динамически.
($int_if:network) и (self) в круглых скобках что бы в выводе pfctl -sn не было подстановки реальных адресов и сетей. Это удобно, когда у вас на внутреннем интерфейсе несколько алиасов и, соответственно, подсетей (как в моем случае).

nat on <span class="variable" style="color: #b58900;">$ext_if</span> inet from (<span class="variable" style="color: #b58900;">$int_if</span>:network) to !(<span class="keyword" style="color: #859900;">self</span>) -> (<span class="variable" style="color: #b58900;">$ext_if</span>) port <span class="number" style="color: #2aa198;">1024</span>:<span class="number" style="color: #2aa198;">65535</span>



Пользователей из группы pc_hipri и pc_pri пускаем в обход прокси. Я пускаю их напрямую, т.к. эти пользователи не нуждаются в контроле, а также специфическое ПО не работает в режиме прозрачного проксирования.

no rdr on $int_if inet proto tcp from {<span class="tag"><<span class="title" style="font-weight: bold; color: #268bd2;">pc_hipri</span>></span> <span class="tag"><<span class="title" style="font-weight: bold; color: #268bd2;">pc_pri</span>></span>} to !(self) port 80



Правило редиректа, перенаправляющие все ДНС-запросы локальных пользователей на
внешний ДНС-сервер. Это может быть Google или, лучше, ДНС-сервер компании,
предоставляющей фильтрацию трафика посредством ДНС.

rdr on <span class="variable" style="color: #b58900;">$int_if</span> inet proto {tcp udp} from (<span class="variable" style="color: #b58900;">$int_if</span>:network) to !(<span class="keyword" style="color: #859900;">self</span>) port <span class="number" style="color: #2aa198;">53</span> -> <span class="number" style="color: #2aa198;">193.58</span>.<span class="number" style="color: #2aa198;">251.251</span> port <span class="number" style="color: #2aa198;">53</span>



Редирект на прокси-сервер.

rdr on <span class="variable" style="color: #b58900;">$int_if</span> inet proto tcp from (<span class="variable" style="color: #b58900;">$int_if</span>:network) to !(<span class="keyword" style="color: #859900;">self</span>) port <span class="number" style="color: #2aa198;">80</span> -> <span class="number" style="color: #2aa198;">127.0</span>.<span class="number" style="color: #2aa198;">0.1</span> port <span class="number" style="color: #2aa198;">31280</span>



Редирект на удаленный рабочий стол виндовой машины в локальной сети из сети Интернет.

rdr on <span class="variable" style="color: #b58900;">$ext_if</span> inet proto tcp from any to (<span class="variable" style="color: #b58900;">$ext_if</span>) port <span class="number" style="color: #2aa198;">3389</span> -> <span class="number" style="color: #2aa198;">10.11</span>.<span class="number" style="color: #2aa198;">1.2</span> port <span class="number" style="color: #2aa198;">3389</span>



Правила фильтрации трафика. Правила будем группировать в такой последовательности: действие, интерфейс, направление, протокол, адрес источника, порт источника, адрес назначения, порт назначения.

Антиспуфинг.

antispoof quick <span class="keyword" style="color: #859900;">for</span> {<span class="variable" style="color: #b58900;">$int_if</span> lo0} inet



Блокируем не маршрутизируемые адреса.

block <span class="keyword" style="color: #859900;">in</span> quick inet from no-route to any



Блокируем броадкасты.

block <span class="keyword" style="color: #859900;">in</span> quick on $ext_if inet from any to <span class="number" style="color: #2aa198;">255.255</span>.<span class="number" style="color: #2aa198;">255.255</span>



Блокируем IP-адреса, содержащиеся в таблице ban. Опция return возвращает TCP RST, что закрывает сразу соединение без таймаута. Полезно, когда блокируются адреса рекламных сетей, что позволяет браузеру нормально загружать странички без ожидания загрузки блокируемого контента.

block return out quick on $ext_if inet from any to <span class="tag"><<span class="title" style="font-weight: bold; color: #268bd2;">ban</span>></span>



Эти 2 правила определяют тип файервола: запрещено все, кроме явно разрешенного.

block <span class="keyword" style="color: #859900;">in</span> all
block out all



Собственно разрешающие правила. 
Расположены в определенной последовательности, что важно с точки зрения производительности, а также ожидаемого эффекта.

Внутренний интерфейс.

Разрешаем ТСР-пакеты к интерфейсу обратной петли, на котором «слушает» прокси-сервер для организации прозрачного проксирования. Назначаем очереди. Мы не можем приоритизировать входящий трафик, только исходящий. В d_pri будут попадать пакеты, которые являются ответом от сервера к клиенту, таким образом мы регулируем скорость скачивания.

pass in <span class="keyword" style="color: #859900;">log</span> quick on <span class="variable" style="color: #b58900;">$int_if</span> inet proto tcp from (<span class="variable" style="color: #b58900;">$int_if</span>:network) to <span class="number" style="color: #2aa198;">127.0</span>.<span class="number" style="color: #2aa198;">0</span>.<span class="number" style="color: #2aa198;">1</span> port <span class="number" style="color: #2aa198;">31280</span> queue (d_pri, d_ack)



Далее 3 правила, которые разрешают ТСР соединения на определенные порты на не локальные IP-адреса. Назначаются соответствующие очереди. Тегирование необходимо что бы потом на внешнем интерфейсе мы могли «отделить» его от остального трафика и направить в нужную очередь. Заметьте, опция quick не используется, поэтому эти правила нужно расположить в правильной последовательности: от менее ограничивающего к более, потому как без опции
quick последнее совпавшее правило выигрывает, а не первое совпавшее.

Опция quick не используется т.к. при совпадении пакет будет назначен в очередь и пропущен и не дойдет до тех правил, которые описывают разрешения и приоритеты, основанные не на протоколах, а на адресах источника/назначения (в нашем случае это компьютеры из группы pc_hipri и pc_pri). Т.к. протокол ТСР, то так же добавляем очередь для ТСР АСК-пакетов. В качестве адреса назначения в правилах фигурирует !(self:network). Это значит, что только пакеты, не предназначенные ни к одному IP-адресу сетевых интерфейсов или IP-адресу из
подсетей, подключенных к роутеру, будут разрешаться и, соответственно, тегироваться. Это, например, не даст подключиться к внешнему IP из локальной сети.

pass in log on <span class="variable" style="color: #b58900;">$int_if</span> inet proto tcp from (<span class="variable" style="color: #b58900;">$int_if</span>:network) to !(<span class="keyword" style="color: #859900;">self</span>:network)
		<span class="variable" style="color: #b58900;">$mst</span> queue (d_other d_ack) tag INET_OTHER
pass in log on <span class="variable" style="color: #b58900;">$int_if</span> inet proto tcp from (<span class="variable" style="color: #b58900;">$int_if</span>:network) to !(<span class="keyword" style="color: #859900;">self</span>:network)
		port {<span class="number" style="color: #2aa198;">20</span> <span class="number" style="color: #2aa198;">21</span> <span class="number" style="color: #2aa198;">25</span> <span class="number" style="color: #2aa198;">110</span> <span class="number" style="color: #2aa198;">143</span> <span class="number" style="color: #2aa198;">5190</span> <span class="number" style="color: #2aa198;">8080</span> <span class="number" style="color: #2aa198;">081</span>} <span class="variable" style="color: #b58900;">$mst</span> queue (d_lowpri d_ack) tag INET_LOWPRI
pass in log on <span class="variable" style="color: #b58900;">$int_if</span> inet proto tcp from (<span class="variable" style="color: #b58900;">$int_if</span>:network) to !(<span class="keyword" style="color: #859900;">self</span>:network)
		port <span class="number" style="color: #2aa198;">443</span> <span class="variable" style="color: #b58900;">$mst</span> queue (d_pri d_ack) tag INET_PRI



Далее 2 правила, которые будут срабатывать как для всех пользователей так и для тех, кто принадлежит к т.н. VIP-группе (pc_hipri и pc_pri). Поэтому тут используем опцию quick.

pass in log quick on <span class="variable" style="color: #b58900;">$int_if</span> inet proto tcp from (<span class="variable" style="color: #b58900;">$int_if</span>:network) to !(<span class="keyword" style="color: #859900;">self</span>:network)
		port {<span class="number" style="color: #2aa198;">22</span> <span class="number" style="color: #2aa198;">3389</span>} <span class="variable" style="color: #b58900;">$mst</span> queue (d_hipri d_ack) tag INET_HIPRI
pass in log quick on <span class="variable" style="color: #b58900;">$int_if</span> inet proto tcp from (<span class="variable" style="color: #b58900;">$int_if</span>:network) to !(<span class="keyword" style="color: #859900;">self</span>:network)
		port <span class="number" style="color: #2aa198;">53</span> <span class="variable" style="color: #b58900;">$mst</span> queue (d_dns d_ack) tag INET_DNS



Следующие 2 правила, по-аналогии с TCP, описывают разрешения и очереди для протокола UDP. Так же их тегируем. Второе правило с опцией quick, т.к. оно должно срабатывать для всех категорий пользователей.

pass in log on <span class="variable" style="color: #b58900;">$int_if</span> inet proto udp from (<span class="variable" style="color: #b58900;">$int_if</span>:network) to !(<span class="keyword" style="color: #859900;">self</span>:network) queue d_other tag INET_OTHER
pass in log quick on <span class="variable" style="color: #b58900;">$int_if</span> inet proto udp from (<span class="variable" style="color: #b58900;">$int_if</span>:network) to !(<span class="keyword" style="color: #859900;">self</span>:network)
		port {<span class="number" style="color: #2aa198;">53</span> <span class="number" style="color: #2aa198;">123</span>} queue d_dns tag INET_DNS



Правило, разрешающее ICMP.

pass in log on <span class="variable" style="color: #b58900;">$int_if</span> inet proto icmp from (<span class="variable" style="color: #b58900;">$int_if</span>:network) to !(<span class="keyword" style="color: #859900;">self</span>:network) queue d_lowpri tag INET_LOWPRI



Следующие правила, разрешающие трафик от клиентов, с высоким и нормальным приоритетом. Весь трафик будет считаться очень высоким (hipri) или высоким (pri) приоритетом (кроме ДНС и ТСР АСК). Здесь мы не указываем протокол, но указываем modulate state, который применяется только для ТСР. Это не будет ошибкой, PF достаточно «умный» и он подставит modulate state для протокола ТСР, и keep state — для всех остальных протоколов.

pass in log quick on $int_if inet from <span class="tag"><<span class="title" style="font-weight: bold; color: #268bd2;">pc_hipri</span>></span> to !(self:network) $mst queue (d_hipri, d_ack) tag INET_HIPRI
pass in log quick on $int_if inet from <span class="tag"><<span class="title" style="font-weight: bold; color: #268bd2;">pc_pri</span>></span> to !(self:network) $mst queue (d_pri, d_ack) tag INET_PRI



Разрешаем локальный Ethernet к внутреннему интерфейсу роутера.

pass in quick on <span class="variable" style="color: #b58900;">$int_if</span> inet from (<span class="variable" style="color: #b58900;">$int_if</span>:network) to (<span class="variable" style="color: #b58900;">$int_if</span>) queue etherq



Теперь опишем разрешающие правила с внутреннего интерфейса роутера в локальную сеть. Если у вас нет редиректа с Интернета в локальную сеть или нет никаких серверов/клиентов, запущенных на самом роутере и требующих доступ в локальную сеть, то эти правила можно не добавлять. 
Первое правило разрешает трафик с Интернета к указанному IP в локальной сети и назначает очень высокий приоритет входящего трафика. Это третье правило (первое — rdr, второе — разрешающее на внешнем интерфейсе) для редиректа (проброса) порта в локальную сеть.

pass out quick on <span class="variable" style="color: #b58900;">$int_if</span> inet proto tcp from !(<span class="keyword" style="color: #859900;">self</span>) to <span class="number" style="color: #2aa198;">10.11</span>.<span class="number" style="color: #2aa198;">1.2</span> port <span class="number" style="color: #2aa198;">3389</span> queue (d_hipri d_ack)



Правило, разрешающее трафик от внутреннего сетевого интерфейса роутера в локальную сеть. Не важно какой протокол. Весь направляется в очередь etherq.

pass out quick on <span class="variable" style="color: #b58900;">$int_if</span> inet from (<span class="variable" style="color: #b58900;">$int_if</span>) to (<span class="variable" style="color: #b58900;">$int_if</span>:network) queue etherq



Внешний интерфейс. Разрешающие правила для входящего трафика.
Важно, для каждого входящего правило указывать максимальное кол-во стейтов, которые может
создать правило. Это предотвратит исчерпывания всего лимита стейтов одним правилом в случае DoS атаки. 
Последующие 6 правил разрешают входящие ТСР-подключения к определенным портам роутера, а также назначаются соответствующие очереди. Эти очереди будут приоритизировать не входящий трафик, а исходящий. Так же стоит обратить внимание на первые два правила, которые разрешают доступ к FTP серверу на роутере. Передача команд по 21-му порту будет направляться в очередь с большим приоритетом (u_pri), а данные — с меньшим (u_lowpri).

pass in quick on $ext_if inet proto tcp from <span class="tag"><<span class="title" style="font-weight: bold; color: #268bd2;">trust</span>></span> to ($ext_if) port 21 $mst (max 100) queue (u_pri u_ack)
pass in quick on $ext_if inet proto tcp from <span class="tag"><<span class="title" style="font-weight: bold; color: #268bd2;">trust</span>></span> to ($ext_if) port >=49152 $mst (max 100) queue (u_lowpri u_ack)
pass in quick on $ext_if inet proto tcp from <span class="tag"><<span class="title" style="font-weight: bold; color: #268bd2;">me</span>></span> to ($ext_if) port 22 $mst (max 10) queue (u_hipri u_ack)
pass in quick on $ext_if inet proto tcp from <span class="tag"><<span class="title" style="font-weight: bold; color: #268bd2;">me</span>></span> to ($ext_if) port 80 $mst (max 100) queue (u_pri u_ack)
pass in quick on $ext_if inet proto tcp from <span class="tag"><<span class="title" style="font-weight: bold; color: #268bd2;">me</span> /></span> to ($ext_if) port 5900 $mst (max 10) queue (u_hipri u_ack)



Правило, разрешающее входящее подключение с сети Интернет (конкретно с адреса администратора), но не к интерфейсам роутера (внешнему в том числе), а к компьютеру в локальной сети к порту RDP.

pass in quick on $ext_if inet proto tcp from <span class="tag"><<span class="title" style="font-weight: bold; color: #268bd2;">me</span>></span> to !(self) port 3389 $mst (max 10) queue (u_hipri u_ack)



Следующее правило разрешает подключение с любого адреса сети Интернет к VNC-репитеру. В целях безопасности включен трекинг источника (source-track). 

pass in quick on <span class="variable" style="color: #b58900;">$ext_if</span> inet proto tcp from any to (<span class="variable" style="color: #b58900;">$ext_if</span>) port <span class="number" style="color: #2aa198;">5500</span> <span class="variable" style="color: #b58900;">$mst</span>
max <span class="number" style="color: #2aa198;">10</span>,<span class="variable" style="color: #b58900;">$str</span>, max-src-nodes <span class="number" style="color: #2aa198;">2</span>, max-src-states <span class="number" style="color: #2aa198;">3</span>, max-src-conn-rate <span class="number" style="color: #2aa198;">3</span>/<span class="number" style="color: #2aa198;">60</span>)
queue (u_hipri u_ack)




Следующие 2 правила разрешают подключения к определенным портам по протоколу UDP.

pass in quick on <span class="variable" style="color: #b58900;">$ext_if</span> inet proto udp from any to (<span class="variable" style="color: #b58900;">$ext_if</span>) port <span class="number" style="color: #2aa198;">1194</span> (max <span class="number" style="color: #2aa198;">20</span>) queue u_pri
pass in quick on <span class="variable" style="color: #b58900;">$ext_if</span> inet proto udp from <sip_peers> to (<span class="variable" style="color: #b58900;">$ext_if</span>) port <span class="number" style="color: #2aa198;">5060</span> (max <span class="number" style="color: #2aa198;">20</span>) queue u_hipri



Разрешаем пинг к внешнему интерфейсу.

pass in quick on <span class="variable" style="color: #b58900;">$ext_if</span> inet proto icmp from any to (<span class="variable" style="color: #b58900;">$ext_if</span>) icmp-type echore<span class="string" style="color: #2aa198;">q (max 100)</span> queue u_other



Внешний интерфейс. Разрешающие правила для исходящего трафика.

Следующие 5 правил разрешают исходящий трафик с внешнего интерфейса, который был помечен на внутреннем интерфейсе. Это исключительно данные, которые передаются в сеть Интернет от клиентов в локальной сети.

pass out quick on <span class="variable" style="color: #b58900;">$ext_if</span> inet from (<span class="variable" style="color: #b58900;">$ext_if</span>) to any <span class="variable" style="color: #b58900;">$mst</span> queue (u_dns u_ack) tagged INET_DNS
pass out quick on <span class="variable" style="color: #b58900;">$ext_if</span> inet from (<span class="variable" style="color: #b58900;">$ext_if</span>) to any <span class="variable" style="color: #b58900;">$mst</span> queue (u_hipri u_ack) tagged INET_HIPRI
pass out quick on <span class="variable" style="color: #b58900;">$ext_if</span> inet from (<span class="variable" style="color: #b58900;">$ext_if</span>) to any <span class="variable" style="color: #b58900;">$mst</span> queue (u_pri u_ack) tagged INET_PRI
pass out quick on <span class="variable" style="color: #b58900;">$ext_if</span> inet from (<span class="variable" style="color: #b58900;">$ext_if</span>) to any <span class="variable" style="color: #b58900;">$mst</span> queue (u_lowpri u_ack) tagged INET_LOWPRI
pass out quick on <span class="variable" style="color: #b58900;">$ext_if</span> inet from (<span class="variable" style="color: #b58900;">$ext_if</span>) to any <span class="variable" style="color: #b58900;">$mst</span> queue (u_other u_ack) tagged INET_OTHER



И последние правила, разрешающие исходящие соединения с внешнего интерфейса.
Это будет трафик непосредственно самого роутера. В целом приоритет этого трафика выше чем от клиентов в локальной сети.

pass out quick on <span class="variable" style="color: #b58900;">$ext_if</span> inet proto tcp from (<span class="variable" style="color: #b58900;">$ext_if</span>) to any port <span class="number" style="color: #2aa198;">53</span> <span class="variable" style="color: #b58900;">$mst</span> queue (u_dns u_ack)
pass out quick on <span class="variable" style="color: #b58900;">$ext_if</span> inet proto tcp from (<span class="variable" style="color: #b58900;">$ext_if</span>) to any <span class="variable" style="color: #b58900;">$mst</span> queue (u_pri u_ack)
pass out quick on <span class="variable" style="color: #b58900;">$ext_if</span> inet proto udp from (<span class="variable" style="color: #b58900;">$ext_if</span>) to any port {<span class="number" style="color: #2aa198;">53</span> <span class="number" style="color: #2aa198;">123</span>} queue u_dns
pass out quick on <span class="variable" style="color: #b58900;">$ext_if</span> inet proto udp from (<span class="variable" style="color: #b58900;">$ext_if</span>) to <sip_peers> port <span class="number" style="color: #2aa198;">5060</span> queue u_hipri
pass out quick on <span class="variable" style="color: #b58900;">$ext_if</span> inet proto udp from (<span class="variable" style="color: #b58900;">$ext_if</span>) to any queue u_pri
pass out quick on <span class="variable" style="color: #b58900;">$ext_if</span> inet proto icmp from (<span class="variable" style="color: #b58900;">$ext_if</span>) to any <span class="variable" style="color: #b58900;">$mst</span> queue u_lowpri



Есть один важный момент, на котором остановлюсь подробнее. Второе правило будет разрешать ТСР-соединения с роутера и в том числе на 80 порт. Под это правило так же подпадают пакеты, отправленные с прокси-сервера, трафик, который фактически является HTTP-трафиком клиентов из локальной сети. Т.к. в нашем случае приоритеты этих видов трафика равны (очередь u_pri), то все хорошо. Но если планируется назначить очереди разные (например, HTTP от локальных клиентов — очередь u_lowpri, а с внешнего интерфейса роутера — u_pri), тогда следует указать в правиле для прокси-сервера опцию user uid и поместить его над
правилом для внешнего интерфейса роутера. Например, прокси запущен с правами пользователя nobody:

pass out quick on <span class="variable" style="color: #b58900;">$ext_if</span> inet proto tcp from (<span class="variable" style="color: #b58900;">$ext_if</span>) to any user nobody <span class="variable" style="color: #b58900;">$mst</span> queue (u_lowpri u_ack)
pass out quick on <span class="variable" style="color: #b58900;">$ext_if</span> inet proto tcp from (<span class="variable" style="color: #b58900;">$ext_if</span>) to any <span class="variable" style="color: #b58900;">$mst</span> queue (u_pri u_ack)



Соответственно, правило, разрешающее доступ к прокси из локальной сети тоже немного измениться: необходимо поменять очередь с d_pri на d_lowpri.

pass in <span class="keyword" style="color: #859900;">log</span> quick on <span class="variable" style="color: #b58900;">$int_if</span> inet proto tcp from (<span class="variable" style="color: #b58900;">$int_if</span>:network) to <span class="number" style="color: #2aa198;">127.0</span>.<span class="number" style="color: #2aa198;">0</span>.<span class="number" style="color: #2aa198;">1</span> port <span class="number" style="color: #2aa198;">31280</span> queue (d_lowpri, d_ack)



Стоить отметить о наличии бага, который проявляется при использованием опции user. Об этом описано в секции BUGS на странице руководства pf.conf. Лично у меня этот баг не проявлялся. Все же старайтесь опцию user не использовать. 

Отладка. Отличительной способностью PF есть его протоколирование, статистика и мониторинг состояния в реальном времени что значительно облегчает конфигурирование файервола, особенно для сложных сетевых топологий.

Просмотр загруженных очередей:

pfctl -sq



Что бы в реальном времени наблюдать загрузку очередей выполните команду:

pfctl -vvsq



Так же рекомендую установить из портов программу pftop, которая по аналогии с утилитой top выводит различную статистику PF в реальном времени.

Количество компьютеров на предприятии постепенно увеличивалось, необходимо было или менять маску подсети, или добавлять дополнительно, еще 3 подсети.
Было принято второе решение, и так поехали. Процесс первоначальной установки FreeBSD описывать не буду (жуем хэндбук).
Схема маршрутизации сети:

 

shema2

shema2

Первым делом добавим необходимые параметры в /etc/rc.conf:

#шлюз по умолчанию, на этот адрес идет все то, что не принадлежит нашей сети.
defaultrouter=«193.15.58.78»#у меня vr0 — сетевушка которая смотрит в мою сеть, все остальное алиасы на разные подсети
ifconfig_vr0=«inet 192.168.0.1 netmask 255.255.255.0»
ifconfig_vr0_alias0=«inet 192.168.1.1 netmask 255.255.255.0»
ifconfig_vr0_alias1=«inet 192.168.2.1 netmask 255.255.255.0»
ifconfig_vr0_alias2=«inet 192.168.3.1 netmask 255.255.255.0»#прописываем статические маршруты
static_routes=«net1 net2 net3 net4»
route_net1=«-net 192.168.0.0/24 192.168.0.1»
route_net2=«-net 192.168.1.0/24 192.168.1.1»
route_net3=«-net 192.168.2.0/24 192.168.2.1»
route_net4=«-net 192.168.3.0/24 192.168.3.1»

#разрешаем маршрутизацию на интерфейсах
gateway_enable=«YES»

Перезагружаемся или выполняем /etc/netstart для перечитывания rc.conf и применения настроек. Теперь все четыре подсети будут доступны между собой.

[root@router ~]# ifconfig
vr0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500
options=8<VLAN_MTU>
ether 00:1c:f0:fb:05:01
inet 192.168.0.1 netmask 0xffffff00 broadcast 192.168.0.255
inet 192.168.1.1 netmask 0xffffff00 broadcast 192.168.1.255
inet 192.168.2.1 netmask 0xffffff00 broadcast 192.168.2.255
inet 192.168.3.1 netmask 0xffffff00 broadcast 192.168.3.255
media: Ethernet autoselect (100baseTX <full-duplex>)
status: active
lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> metric 0 mtu 16384
inet6 fe80::1%lo0 prefixlen 64 scopeid 0×5
inet6 ::1 prefixlen 128
inet 127.0.0.1 netmask 0xff000000

Указываем наш сервер в качестве шлюза для всех ПК из этих сетей.

В мемориз:
Настройка маршрутов при помощи команды route

Добавляем шлюз по умолчанию:

route add default 192.168.17.77

Удалить шлюз по умолчанию:

route del default

Добавить маршрут в сеть 10.10.0.0/16 (маска 255.255.0.0) через gateway 10.10.1.1/24

route add 10.10.0.0/16 10.10.1.1

Другой вариант добавление такого же маршрута

route add -net 10.10.0.0 -netmask 255.255.0.0 10.10.1.1

Удалить маршрут:

route delete 10.10.0.0/16

Посмотреть имеющиеся в системе маршруты

netstat -rn