Во FreeBSD для включения PF указываем в /etc/rc.conf:
pf_enable="YES"При необходимости выделения гарантированной полосы пропускания для голосового трафика задействуем ALTQ.
Пересобираем ядро с поддержкой ALTQ, указав в конфигурации:
options ALTQ
options ALTQ_CBQ # Class Bases Queuing (CBQ)
options ALTQ_RED # Random Early Detection (RED)
options ALTQ_RIO # RED In/Out
options ALTQ_HFSC # Hierarchical Packet Scheduler (HFSC)
options ALTQ_PRIQ # Priority Queuing (PRIQ)
options ALTQ_NOPCC # Required for SMP buildДалее для организации NAT для машин с SIP телефонами используем следующие настройки пакетного фильтра (/etc/pf.conf):
# Вернет ошибку, порт заблокирован
set block-policy return
# тайм-аут UDP сессии должен быть равен или больше, чем время регистрации SIP
# Таймер тайм-аута. Обычно достаточно 300 секунд.
set timeout { udp.first 300, udp.single 150, udp.multiple 900 }
# переменные
int_if = "fxp0"
ext_if = "fxp1"
int_net = "192.168.1.0/24"
ipphone1 = "192.168.1.18"
ipphone2 = "192.168.1.19"
# Включим очереди для внешнего интерфейса. Отделим голосовой трафик от данных
altq on $ext_if hfsc bandwidth 512Kb queue { q_voice, q_other }
queue q_voice bandwidth 3.84Kb priority 6 hfsc(realtime 96Kb)
queue q_other bandwidth 416Kb hfsc { q_pri, q_std, q_low }
queue q_pri bandwidth 200Kb priority 3 hfsc(red realtime 64Kb)
queue q_std bandwidth 200Kb priority 2 hfsc(default red )
queue q_low bandwidth 3.84Kb priority 1 hfsc(red )
# Для каждого IP- телефона свое правило трансляции nat.
# Параметр static-port нужен для сохранения временного порта UDP.
# Это нужно чтобы удаленный SIP прокси знал к какой сессии привязан наш IP телефон.
nat on $ext_if proto udp from $ipphone1 to any -> ($ext_if) static-port
nat on $ext_if proto udp from $ipphone2 to any -> ($ext_if) static-port
# Правило NAT для остальных устройств локальной сети
nat on $ext_if from $int_net to any -> ($ext_if)
pass in quick on lo0 all
pass out quick on lo0 all
# Разрешаем SIP трафик с телефонов на локальном интерфейсе
pass in quick on $int_if proto udp from $ipphone1 to any tag VOIP keep state
pass in quick on $int_if proto udp from $ipphone2 to any tag VOIP keep state
pass in quick on $ext_if proto tcp from any to any port 22 keep state \
queue(q_std,q_pri)
pass in quick on $ext_if proto tcp from any to any port 80 keep state \
queue q_low
pass out quick on $ext_if tagged VOIP queue q_voice keep state
pass out quick on $ext_if proto tcp from any to any port 22 keep state \
queue(q_std,q_pri)
pass out quick on $ext_if proto tcp from any to any flags S/SA keep state \
queue(q_std,q_pri)
pass out quick on $ext_if proto udp from any to any port 53 queue q_pri \
keep state
# Разрешаем с внешнего интерфейса наружу tcp, udp, icmp
pass out quick on $ext_if proto { tcp, udp, icmp } all keep state
block in log all
Конфигурация была протестирована на VoIP телефоне Cisco 7960,
NAT прокси и outbound_proxy не используются, в телефоне настроен прокси-сервер SIP и порт контроля 5060/udp. Функция STUN в телефоне включена, хотя некоторые коммерческие SIP-прокси могут работать без него.Проверить очереди:
pfctl -vsq -vОчистить таблицы состояний:
pfctl -F stateПроверка правил:
pfctl -s rules -v
URL: http://www.arg.su/ru-RU/node/128 http://www.bastard.net/~kos/pf-voip.html
Обсуждается: http://www.opennet.me/tips/info/2220.shtml
а если телефонов 200-300 штук?
а вот поэтому и не стоит использовать BSD на шлюзах общего назначения, там с pf сюрпризов ой как много вылазит
Конкретно, каких сюрпризов?
А что за сюрпризы с PF?
>а вот поэтому и не стоит... а вот по этому и не стоит говорить о чём не ведаешь :)
ну да, ну да....
SIP и GRE via NAT, route-to и 3-4 линка. Это то что вспомнил с ходу. Сам использую PF(OpenBSD) но только там где заранее знаю требуемый набор функций.
Макросы/переменные нужно выносить в первые строчки!Флажки "flags S/SA" и "keep state" можно не указывать — оно и так подразумевается по умолчанию.
Конструкцию "block in log all" нужно ставить ПЕРЕД разрешающими правилами, сразу после описания трансляций NAT, и лучше заменить на тупое и беспринципное "block all", когда всё отлажено и логи ни к чему.
Набор правил:
pass in quick on lo0 all
pass out quick on lo0 all
достаточно заменить на одну ОПЦИЮ:
set skip on { lo }"scrub in all" до описания очередей ОБЯЗАТЕЛЬНО!
из того, что вспомнилне работает synproxy на tun интерфейсах, по крайней мере в 7.0-7.2 не работало, а это означает что если повесить на внешний интерфейс(tun) ssh то контроллировать средствами pf атаки bruteforce - не представляеться возможным.
а вообще соглашусь что подводных камней ой как много, лучше использовать ipfw, но он не так "красив" и легок для начинающих.
с работой ftp есть проблемы в определенных режимах
linux box
и
sudo modprobe nf_nat_sip
решат проблемы с натом сипа
Во-во! Я так же решил эту проблему.А что-то дико сложно это делается в PF.
> sudo modprobe nf_nat_sipНекоторым простые решения кажутся неспортивными :-)
Как вариант - натить SIP и GRE трафик с помощью IPFW, а остальное гонять через PF.З.Ы. Для кричащих "нахрена два фаерволла" - каждый фаер делает то что он умеет, pf - плюшки вроде route-to и reply-to, IPFW - натить проблемный трафик.
>pf - плюшки вроде route-to и reply-toа что, на ipfw это совершенно невозможно сделать? :)
если покажете как сделать аналог reply-to в ipfw буду век вам благодарен
отошлю к статье Вадима Гончарова:http://nuclight.livejournal.com/124348.html
Тот факт, что на самом деле "перепрыгивание" выполняется на параметры
действия, позволяет использовать это для интересных вещей. В частности, с
использованием появившегося во FreeBSD 6.2 параметра tag на каждый пакет можно
навешивать внутриядерный тег, что в применении со skipto позволяет сделать, к
примеру, запоминание, с какого шлюза пришел входящий пакет на машине с каналами
к двум разным провайдерам, и ответные пакеты отправлять в тот канал, откуда они
пришли (допустим, у вашей машины только один IP-адрес, и сделать fwd на базе
внешнего адреса не получится), т.е. реализовать аналог reply-to из pf:ipfw add 100 skipto 300 tag 1 in recv $ext_if1 keep-state
ipfw add 200 skipto 300 tag 2 in recv $ext_if2 keep-state
ipfw add 300 allow { recv $ext_if1 or recv $ext_if2 } # входящие снаружи
ipfw add 400 allow in recv $int_if # разрешить ответы на внутреннем проходе
ipfw add 500 fwd $gw1 tagged 1 # остались ответы на внешнем интерфейсе,
ipfw add 600 fwd $gw2 tagged 2 # зарулим их куда надо
Н-да .. тяжко оно без natd ..
зачем оно нужно?