Freeswitch: по пути наименьшего сопротивления

Немного лирики

Сколько помню себя в кресле системного администратора (а общий стаж приближается уже годам к 15), столько вопросы офисной телефонии воспринимались мной строчкой из Californication калифорнийских же RHCP: hard core soft porn. Телефония всегда казалась параллельным измерением, в ее администрирование и настройку я старался не лезть. Точнее, вообще обходить все эти телефоновопросы по широкой дуге, скидывая все подобные задачи на «специально обученных людей».

Однако, как часто бывает, сколько веревочке не виться, а конец один… После трудоустройства в новой организации я стал «счастливым» администратором прекрасной связки из цифро-аналоговой АТС Ericsson и «маршрутизатора с интегрированными сервисами» Cisco 2911. Более сотни аналоговых телефонов, три десятка цифровых Ericsson’ов и два-три десятка IP-телефонов Cisco и Ericsson. Все это великолепие некогда было настроено теми самими спецами по hard core soft porn, и как оно работает, я и по сей день представляю лишь в общих чертах. Однако, как бы то ни было, что такое extension, как организовывается условная и безусловная переадресация, как устроен IVR, что такое DID и прочее, узнать мне все же пришлось. И я не был в восторге от обретенных знаний (да-да, не все полезное интересно и приятно). Лишь циска, после усвоения мною логики ее настройки, стала более или менее приятной железякой.

В какой-то момент пришло смирение, что телефония все же неотъемлемая часть хозяйства системного администратора.

И грянул гром

Организация, в которой я работаю, переезжает в другое здание. Разумеется, все аналоговое и цифровое хозяйство остается по месту вечной прописки. Цисковский VoIP в приготовлении 2911 обеспечивает 50 линий, да и ценник на телефонные аппараты циско совершенно негуманный. И то ли благодаря уже пришедшему смирению, то ли благодаря врожденной тяге к знанию, то ли благодаря сочетанию этих двух факторов я решил, что на новом месте телефонию я подниму сам.

Требования были простые: дешево, а лучше бесплатно, а, в идеале, чтобы нам доплачивали, обеспечить базовый функционал (прямые городские номера у сотрудников, IVR, переадресация, конференции, перевод вызова), от 150 линий и выше. Первое слово, пришедшее в голову, было «SIP», второе «Asterisk», третье «Гугл».

Был скачан и развернут AsteriskNOW. Ошалело потыкался в веб-интерфейсе. Оценил в который раз hardcornsoftporn’овскую логику телефонистов и снова отправился гуглить. И случайно натолкнулся на слово «FreeSWITCH». Новое слово, новые поисковые запросы. Хвалебные оды устойчивости, легкости настройки (всюду XML), нетребовательности к ресурсам, плюс работа «из коробки», плюс «у людей» без нареканий работает в виртуальном окружении с сотнями и даже тысячами линий без искажений голоса (хотя разработчики и не рекомендуют виртуальное окружение в связи с отсутствием доступа к CPU в реальном режиме времени). Ок. Пробуем.
Поднимаем виртуальную машину под рекомендованным Debian 8 x64, 1 ядро 2ГГц, 2 гига оперативки, 16 гиг диск. Выполняем установку в соответствии с инструкцией (тыц). Настраиваем софтфон (мне понравился 3CX’овский тыц).

Софтфон зарегистрировался. Тестовые звонки пошли. Ляпота. Ericsson Dialog 4422 тоже зарегистрировался, звонит, голос слышен в обе стороны. Ляпота. Аппарату Cisco 7945 была поставлена прививка прошивкой с поддержкой SIP, и, после относительно непродолжительных танцев с настройкой SCCP, аппарат так же зарегистрировался и звонки пошли без нареканий. Ляпота. FreeSWITCH в продакшн!

Хватит лирики

Исходные данные:

Оборудование коммутационной первого этажа:

  1. Коммутатор в собственности МТС, на котором нам выделена группа портов. С него мы забираем инет и будем забирать SIP-телефонию. Трафик тегирован vlan4
  2. Коммутатор наш, у него выделена группа портов, которым назначены vlan. В эти порты приходит инет от МТС (порт 2 — vlan2), инет от Miralogic (порт 3 — vlan3), SIP от МТС (порт 4 — vlan4). Так же выделен порт 1 под trunk, кабель уходит в серверную четвертого этажа.

Оборудование серверной на четвертом этаже:

  1. Коммутатор, принимающий trunk с первого этажа. Порт 1 — trunk входящий (с первого этажа. Порт 2 — trunk исходящий (к серверу).
  2. Сервер, на нем VMware vSphere 6. На этом хосте гостевая машина с Mikrotik RouterOS, выполняющая роль шлюза и файервола. Так же на этом хосте гостевая машина с FreeSWITCH. На хосте настроен vSwitch и добавлены порты с соответствующим тегированием трафика: vlan2, vlan3, vlan4.

Телефонию по E1 нам предоставляет МТС. От МТС же был предоставлен на тест SIP-транк.
Вот такие настройки были присланы мне инженерами МТС:

Добрый день! Реквизиты SIP транка Порт на коммутаторе 9 Номер 5555555 ip-адрес: 172.16.160.154 маска: 255.255.255.252 шлюз: 172.16.160.153 соединение без регистрации, точка - точка sip-сервер: 172.16.253.3, port: 5060 UDP media-сервер: 172.16.253.4, port: 10000 - 30000 UDP кодеки: G711a/u протокол передачи DTMF: rfc-2833

Машина с FreeSWITCH имеет один сетевой интерфейс, сетевые настройки:

IP: 172.18.253.1 Netmask: 255.255.0.0 GW: 172.18.1.254

Полетели, Mikrotik

Гасим гостевую машину с Mikrotik’ом и добавляем еще один сетевой интерфейс, назначаем ему vlan4. Включаем гостевую машину, Mikrotik загружается, видим, что новый интерфейс появился.

Настраиваем.

Настройка интерфейса в Mikrotik

Выводим список имеющихся интерфейсов:
/interface ethernet print

Видим, что свежедобавленный интерфейс это интерфейс с именем ether6
Переименовываем его в if-sip:
/interface ethernet set [ find default-name=ether6 ] name=if-sip

Настраиваем адрес:
/ip address add address=172.16.160.154/30 comment=mts-sip interface=if-sip network=172.16.160.152

Настраиваем маршрутизацию в Mikrotik

Настраиваем mangle (чтобы трафик маркировался как мы захотим, и чтобы трафик ходил только через нужный нам интерфейс на основе этих меток):
/ip firewall mangle add action=mark-routing chain=prerouting comment="mark sip traffic" new-routing-mark=sip src-address=172.18.253.1

Настраиваем маршрутизацию:
/ip route add comment=mts-sip distance=1 dst-address=172.16.0.0/16 gateway=172.16.160.153 routing-mark=sip

Настраиваем файервол и NAT в Mikrotik

Настраиваем отсутствие фильтрации файерволом (на этом этапе я не боюсь злых хакеров из SIP-транка с PAN-адресов МТС):
/ip firewall filter
add chain=forward comment="allow any to mts-sip" dst-address=172.16.0.0/16 in-interface=if-local out-interface=if-sip src-address=172.18.253.1
add chain=forward comment="allow any from mts-sip" dst-address=172.18.253.1 in-interface=if-sip out-interface=if-local src-address=172.16.0.0/16

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

Для себя я решил, что мой SIP-шлюз будет находиться в локальной сети, чтобы:

  • Не иметь трахомудии с нежеланием отдельных телефонных аппаратов работать со шлюзом, находящимся за NAT.
  • Внутренний трафик в десятки раз превышает исходящий и входящий вместе взятые,
    ни к чему его гонять через Mikrotik.
  • И вообще, настроить один раз шлюз будет дальновидней, чем в дальнейшем воевать с множеством телефонных аппаратов (сотни) с разными прошивками, а то и разных производителей.

По этой причине настраиваем 1:1 NAT.
/ip firewall nat
add action=netmap chain=srcnat comment="source NAT for sip" src-address=172.18.253.1 to-addresses=172.16.160.154
add action=netmap chain=dstnat comment="destination NAT for sip" dst-address=172.16.160.154 to-addresses=172.18.253.1

Если отключали сервисные порты, включаем sip обратно:
/ip firewall service-port set sip ports=5060,5061,5080,5081 disabled=no

Пингуем шлюз (172.16.160.153), пингуем SIP-шлюз (172.16.253.3), пингуем Media-шлюз (172.16.253.4). Пинги ходят. Прекрасно.

На этом легкая и понятная часть закончилась.

Полетели, FreeSWITCH

Для «выхода в свет» нам потребуется сделать следующие вещи, названия которых чужды уху айтишника, не сталкивавшегося с телефонией:

  • Указать, какие IP-адреса и где использовать FreeSWITCH’у для установления соединений.
  • Указать код региона и абонентский номер, выделенный оператором.
  • Создать extension — абонентский номер. Из коробки FreeSWITCH имеет преднастроенные 30 абонентских номеров. Мы создадим еще один.
  • Создать шлюз. Это не то, что вы подумали. Шлюз — это именованный набор настроек, необходимый для соединения с предоставленным SIP-транком. Мы же этого делать не будем,
    мы изменим настройки дефолтового шлюза
  • Настроить dialplan. В транслитерации ужасно звучащее слово. В правильном произношении звучащее еще хуже. Мне не нравится. В устоявшемся написании и произношении «диалплан». Означает набор сценариев. Из этого набора в зависимости от сработавшего условия FreeSWITCH выполняет то или иное действие. Диалпланы создаются для исходящих и входящих вызовов.
  • Настроить ACL для сетей и доменов, откуда разрешены звонки.

Disclaimer: предполагается, что FreeSWITCH установлен в папку по умолчанию: /etc/freeswitch

Самое первое, что делаем, меняем дефолтный пароль. Но опять не потому, почему вы подумали. Хотя и поэтому тоже. Пароль проверяется диалпланом, и если пароль совпадает с дефолтным, то перед соединением вставляется пауза 10 сек. Поэтому сначала меняем пароль.
Файл: /etc/freeswitch/vars.xml

<X-PRE-PROCESS cmd="set" data="default_password=ballsofsteel"/>

Как вариант, если вам так уж нравится пароль «1234», то можете убрать паузу из диалплана, просто отредактировав соответствующий блок.
Файл: /etc/freeswitch/dialplan/default.xml

<condition field="${default_password}" expression="^1234$" break="never">   <action application="log" data="Fuck pretense just let's dance"/>   <action application="log" data="Never Open $${conf_dir}/vars.xml and change default password."/> </condition>

Настройки IP-адресов
Файл: /etc/freeswitch/sip_profiles/external.xml

<param name="ext-rtp-ip" value="172.16.160.154"/> <param name="ext-sip-ip" value="172.16.160.154"/>

Региональные настройки
Файл: /etc/freeswitch/vars.xml

<X-PRE-PROCESS cmd="set" data="outbound_caller_name=3435555555"/> <X-PRE-PROCESS cmd="set" data="outbound_caller_id=3435555555"/> <X-PRE-PROCESS cmd="set" data="default_areacode=343"/> <X-PRE-PROCESS cmd="set" data="default_country=RU"/>

Реквизиты от оператора
Файл: /etc/freeswitch/vars.xml

<X-PRE-PROCESS cmd="set" data="default_provider=172.16.253.3"/> <X-PRE-PROCESS cmd="set" data="default_provider_username=3435555555"/> <X-PRE-PROCESS cmd="set" data="default_provider_password=not-used"/> <X-PRE-PROCESS cmd="set" data="default_provider_from_domain=172.16.253.3"/> <X-PRE-PROCESS cmd="set" data="default_provider_register=true"/> <X-PRE-PROCESS cmd="set" data="default_provider_contact=73435555555"/>

Ремарка самым внимательным

Вы, наверное, только что заметили, что значение параметра default_provider_register немного не вяжется с теми настройками, что выдал оператор (соединение без регистрации, точка — точка). Однако, в случае с МТС, регистрация все же понадобилась, без нее не проходили вызовы извне внутрь. При том, что без регистрации вполне можно было звонить изнутри наружу. Эта особенность выпила мне немало крови, прежде, чем я врубился и отловил ее.

Характерным признаком того, что требуется авторизация, является ошибка 407 Proxy Authentication Required.

Отлавливается эта ошибка включением SIP-трассировки:
sofia global siptrace on

Выключается трассировка, соответственно:
sofia global siptrace off

Добавляем абонентский номер (extension)
Создаем xml-файл с любым именем в папке /etc/freeswitch/directory/default. Я создал файл с именем, совпадающим с номером.
Файл: /etc/freeswitch/directory/default/4545.xml

<include>  <user id="4545">    <params>     <param name="password" value="$${default_password}"/>     <param name="vm-password" value="4545"/>    </params>    <variables>     <variable name="toll_allow" value="domestic,international,local"/>     <variable name="accountcode" value="4545"/>     <variable name="user_context" value="default"/>     <variable name="effective_caller_id_name" value="Скудицкий М.В."/>     <variable name="effective_caller_id_number" value="4545"/>     <variable name="outbound_caller_id_name" value="$${outbound_caller_name}"/>     <variable name="outbound_caller_id_number" value="$${outbound_caller_id}"/>     <variable name="callgroup" value="techsupport"/>    </variables>  </user> </include>

Создаем шлюз
Скорее всего, после того, как вы выполнили настройки IP-адресов и заполнили поля в vars.xml реквизитами, выданными оператором, регистрация на шлюзе оператора состоится без проблем.

У меня же «без проблем» не получилось, поскольку МТС реквизиты выслал, а абонентский номер (extension) 3435555555 не завел. Прежде, чем я заподозрил оператора в подставе, я успел перебрать миллион вариантов настройки шлюза. Однако в итоге оператор у себя на SIP-шлюзе абонентский номер создал, и все завелось если и не с дефолтными настройками, то с близкими. Привожу листинг файла mts.xml, который был получен путем переименования файла external.xml.
Файл: /etc/freeswitch/directory/default/mts.xml

<include> <user id="$${default_provider}">   <gateways>    <gateway name="$${default_provider}">     <param name="username" value="$${default_provider_username}"/>     <param name="password" value="$${default_provider_password}"/>     <param name="from-user" value="$${default_provider_username}"/>     <param name="from-domain" value="$${default_provider_from_domain}"/>     <param name="expire-seconds" value="600"/>     <param name="register" value="$${default_provider_register}">     <param name="retry-seconds" value="30"/>     <param name="extension" value="$${default_provider_contact}"/>     <param name="context" value="public"/>    </gateway>   </gateways>  <params>   <param name="password" value="$${default_provider_password}"/>  </params>  </user> </include>

Теперь добавляем разрешения на домен и на сети, чтобы наш FreeSWITCH не блокировал попытки установить соединения из домена и из сетей оператора. И да, на данном этапе я так же просто разрешаю все. Моя задача — позвонить уже наконец за пределы организации.
Файл: /etc/freeswitch/autoload_configs/acl.conf.xml

<list name="lan" default="allow">  <node type="allow" cidr="172.18.0.0/16"/>  <node type="allow" cidr="172.16.0.0/16"/> </list> <list name="domains" default="allow">  <node type="allow" domain="172.18.253.1"/>  <node type="allow" domain="172.16.253.3"/>  <node type="allow" cidr="172.16.0.0/16"/>  <node type="allow" cidr="172.18.0.0/16"/> </list>

Обратите внимание! Это не файервол. Фильтрации трафика не происходит. Это списки доступа к сервисам FreeSWITCH’а.

Поздравляю! Можно посмотреть, что у нас (не) получилось.
Запускаем консоль FreeSWITCH’а:
fs_cli -rRS
Перезагружаем xml’ки:
reloadxml или жмакаем F6
Перезагружаем модуль Sofia, отвечающий за телефонные соединения:
reload mod_sofia
Смотрим, что у нас с соединениями со шлюзами.

freeswitch@phone> sofia status
Name Type Data State
=================================================================================================
external profile sip:mod_sofia@172.16.160.154:5080 RUNNING (0)
external::172.16.253.3 gateway sip:3435555555@172.16.253.3 REGED
172.18.253.1 alias internal ALIASED
internal profile sip:mod_sofia@172.18.253.1:5060 RUNNING (0)
=================================================================================================
2 profiles 1 alias

Славно. Регистрация на шлюзе оператора прошла успешно.
Смотрим подробности:
sofia status gateway 172.16.253.3

freeswitch@phone> sofia status gateway 172.16.253.3
==============================================================
Name 172.16.253.3
Profile external
Scheme Digest
Realm 172.16.253.3
Username 3432788299
Password yes
From <sip:3435555555@172.16.253.3>
Contact <sip:gw+172.16.253.3@172.16.160.154:5080;transport=udp;gw=172.16.253.3>
Exten 73435555555
To sip:3435555555@172.16.253.3
Proxy sip:172.16.253.3
Context public
Expires 600
Freq 600
Ping 0
PingFreq 0
PingTime 0.00
PingState 0/0/0
State REGED
Status UP
Uptime 3932s
CallsIN 1
CallsOUT 1
FailedCallsIN 0
FailedCallsOUT 0
==============================================================

Дело встало за малым.

Диалпланы
Для звонков наружу создаем файл mts.xml с нуля, все остальные файлы в папке /etc/freeswitch/dialplan/default можно переименовать со сменой расширения/перенести в другое место/грохнуть.
Файл: /etc/freeswitch/dialplan/default/mts.xml

<include><extension name="outbound-city-call">  <condition field="${toll_allow}" expression="local"/>  <condition field="destination_number" expression="^(\d{7})$">   <action application="set" data="effective_caller_id_number=${outbound_caller_id_number}"/>   <action application="set" data="effective_caller_id_name=${outbound_caller_id_name}"/>   <action application="bridge" data="sofia/gateway/${default_gateway}/8${default_areacode}$1"/>  </condition> </extension> <extension name="outbound-country.cellular-call">  <condition field="${toll_allow}" expression="domestic"/>  <condition field="destination_number" expression="^8(\d{10})$">   <action application="set" data="effective_caller_id_number=${outbound_caller_id_number}"/>   <action application="set" data="effective_caller_id_name=${outbound_caller_id_name}"/>   <action application="bridge" data="sofia/gateway/${default_gateway}/8$1"/>  </condition> </extension> <extension name="outbound-international-call">  <condition field="${toll_allow}" expression="international"/>  <condition field="destination_number" expression="^(810\d+)$">   <action application="set" data="effective_caller_id_number=${outbound_caller_id_number}"/>   <action application="set" data="effective_caller_id_name=${outbound_caller_id_name}"/>   <action application="bridge" data="sofia/gateway/${default_gateway}/810$1"/>  </condition> </extension> </include>

Для звонков снаружи внутрь создаем файл mts_inbound.xml в папке /etc/freeswitch/dialplan/public. Остальное в этой папке по аналогии выше можно переименовать в *.bck или в *.noload
Файл: /etc/freeswitch/dialplan/public/mts_inbound.xml

<include>  <extension name="public_did">   <condition field="destination_number" expression="^(73435555555)$">    <action application="set" data="domain_name=$${domain}"/>    <action application="transfer" data="4545 XML default"/>        </condition>   </extension> </include> 

Ну что. Скрестили пальцы, проверяем.

Снова запускаем консоль FreeSWITCH’а:
fs_cli -rRS
Перезагружаем xml’ки:
reloadxml или жмакаем F6
Перезагружаем модуль dialplan, отвечающий за телефонные соединения:
reload mod_dialplan_xml
Пробуем дозвон изнутри наружу. Пробуем дозвон снаружи внутрь. Радостно повторяем тестовое «раз-раз, два-два», убеждаемся, что звук ходит в обе стороны. Проверяем прохождение сигналов отбоя в обе стороны.

Радуемся, что приобщились к soft porn.

P.S.: Я сознательно избегал расшифровки значения тех или иных правок. Отчасти, потому что имена параметров и системных переменных очень уж хорошо говорят за себя. Отчасти, чтобы не превращать турбо-запуск телефонии в нудятину с оправданиями каждого пука.

P.P.S.: Написание сего текста было продиктовано ужасом от того, что я так и не смог найти внятный мануал слитным текстом, где решалась бы такая же задача: максимально просто, максимально быстро поднять телефонию с авторизацией точка-точка. Обилие документации почему-то не сопровождается обилием обсуждений и живых примеров. Или просто так получилось, что я допетрил до всего быстрее, чем нагуглил «тот самый пример», который бы сработал у меня. Так или иначе, пусть это будет шпаргалкой для меня и коллег на будущее.

FavoriteLoadingДобавить в избранное

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *