company_banner

Виртуальная АТС. Часть 3: Переводим Asterisk на PjSIP без лишних телодвижений

  • Tutorial


В первой и второй частях цикла статей мы разобрались с установкой IP-АТС (IP-PBX) на работающий под управлением Ubuntu VPS от RuVDS и настройкой основных функций с использованием канального драйвера chan_sip. Этот подход считается устаревшим, и в будущих версиях Asterisk поддержка chan_sip будет прекращена. Вместо него лучше использовать открытую мультимедийную библиотеку PjSIP. Несмотря на кардинальные различия в файлах конфигурации, переход не так сложен, как может показаться на первый взгляд.

Что такое PjSIP?


Важно понимать, что PjSIP — не какой-то новый протокол, а целая библиотека для работы со стеком обеспечивающих голосовую связь протоколов: SIP, RTP, SDP, STUN и т.д. Она представляет собой целую кучу модулей, что нашло отражение в конфигурационном файле pjsip.conf (он заменяет традиционный sip.conf). Файл разделен на секции, а работает с ним преимущественно модуль res_pjsip, при этом каждая секция определяет конфигурацию некоторого объекта. Имена секций традиционно заключаются в квадратные скобки, а в секции обязательно присутствует определяющая ее тип конструкция «type =».

Типы секций могут быть следующими:

ENDPOINT — аналог пира в sip.conf, который определяет опции протокола SIP и взаимодействие с AOR, AUTH и TRANSPORT. Обязательно связана хотя бы с одной секцией AOR;
AOR — здесь описано, как связаться с ENDPOINT;
TRANSPORT — в этой секции описываются настройки протоколов транспортного уровня, веб-сокеты и методы шифрования (наподобие general в sip.conf). Может быть одной для разных ENDPOINT или уникальной для некоторой точки;
REGISTRATION — отвечает за исходящие регистрации, например, транки к провайдерам;
AUTH — содержит опции и полномочия для входящих и исходящих регистраций. С ней ассоциируются ENDPOINT и REGISTRATIONS;
IDENTIFY — здесь можно задать IP источника для ENDPOINT;
ACL — используется res_pjsip для контроля входящих соединений, не привязан к ENDPOINT;
DOMAIN_ALIAS — псевдонимы домена;
CONTACT — нужна, чтобы явно не указывать SIP URI в Dialplan;
System — системные опции;
Global — глобальные опции;

Имена секций в большинстве случаев могут быть произвольными, но, к примеру, ENDPOINT и AOR должны именоваться идентично с заголовком SIP URI.

Нашу справку трудно назвать исчерпывающей, поскольку за кадром осталось много интересных фишек, вроде PjSIP Configuration Wizard: пока речь идет о миграции на новую библиотеку малой кровью. С нюансами и тонкостями можно разобраться позднее.

Конвертируем sip.conf в pjsip.conf


Из-за модульности структура конфигурационного файла pjsip.conf размазана тонким слоем по множеству секций — она гораздо сложнее, чем у старого-доброго sip.conf. Разработчики Asterisk подумали о простых админах и создали сценарий для конвертации. Написан он на Python, и если вы собираете ПО из исходников, уже есть в дистрибутиве: в каталоге contrib/scripts/sip_to_pjsip/. Мы ставили Asterisk из входящего в репозиторий Ubuntu бинарного пакета, поэтому скрипты пришлось скачать с GitHub.

Хотя формат конфигурационных файлов для разных версий IP-PBX особо не менялся, лучше выбрать скрипты из установленной у вас версии Asterisk вместо последней по умолчанию — в нашем случае 16.2.


Версию Asterisk можно посмотреть в консоли IP-PBX с помощью команды core show version

Вам понадобятся все файлы на Python из каталога contrib/scripts/sip_to_pjsip/ в репозитории на GitHub. Их нужно сложить в локальный каталог, перейти в каталог с конфигами Asterisk (обычно /etc/asterisk) и запустить скрипт sip_to_pjsip.py с привилегиями суперпользователя. Основная его задача, прочитать входной файл sip.conf и сделать новый pjsip.conf (подробности доступны в wiki Asterisk).


Сценарий сделает pjsip.conf, а дальше вас ждет его ручная полировка. Если вы устанавливали Asterisk по нашим статьям, придется еще настроить загрузку модулей в /etc/asterisk/modules.conf и изменить в Dialplan (/etc/asterisk/extensions.conf) вызов приложения Dial.

Сделанный конвертером файл /etc/asterisk/pjsip.conf на практике оказался нерабочим:

pjsip.conf
;--
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Non mapped elements start
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

[general]
allowoverlap = no

[office]
call-limit = 2

[sipnet]
remotesecret = пароль

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Non mapped elements end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
--;


[transport-udp]
type = transport
protocol = udp
bind = 0.0.0.0

[sipnet]
type = aor
contact = sip:логин@sipnet.ru

[sipnet]
type = identify
endpoint = sipnet
match = sipnet.ru

[sipnet]
type = endpoint
context = sipnet-trunk
dtmf_mode = rfc4733
disallow = all
allow = alaw,ulaw
direct_media = no
from_user = логин
from_domain = sipnet.ru
aors = sipnet

[1001]
type = aor
max_contacts = 1

[1001]
type = auth
username = 1001
password = пароль

[1001]
type = endpoint
context = homeoffice
dtmf_mode = rfc4733
disallow = all
allow = ulaw
allow = alaw
allow = g729
allow = g723
allow = g726
allow = h261
allow = h263
allow = h264
allow = h263p
callerid = Директор <1001>
auth = 1001
outbound_auth = 1001
aors = 1001

[acl]
type = acl
permit = XXX.XXX.XXX.XXX
deny = 0.0.0.0/0.0.0.0

[1002]
type = aor
max_contacts = 1

[1002]
type = auth
username = 1002
password = пароль

[1002]
type = endpoint
context = homeoffice
dtmf_mode = rfc4733
disallow = all
allow = ulaw
allow = alaw
allow = g729
allow = g723
allow = g726
allow = h261
allow = h263
allow = h264
allow = h263p
callerid = Секретарь <1002>
auth = 1002
outbound_auth = 1002
aors = 1002


Синтаксис его понятен, подробности можно найти в wiki Asterisk. Чтобы довести конфигурационный файл до ума, потребуется ручная правка.

Исправленный /etc/asterisk/pjsip.conf (как и в sip.conf, в нем можно использовать шаблоны):

Исправленный /etc/asterisk/pjsip.conf
;===============TRANSPORT

[transport-udp]
type = transport
protocol = udp
bind = 0.0.0.0

;===============ACL

[acl]
type = acl
deny = 0.0.0.0/0.0.0.0
permit = XXX.XXX.XXX.XXX

;===============SIPNET TRUNK

[sipnet]
type = registration
transport = transport-udp
outbound_auth = sipnet
server_uri = sip:sipnet.ru
client_uri = sip:логин@sipnet.ru
retry_interval = 60

[sipnet]
type = auth
auth_type = userpass
password = пароль
username = логин

[sipnet]
type = aor
contact = sip:логин@sipnet.ru

[sipnet]
type = endpoint
transport = transport-udp
; Контекст должен быть прописан в Dialplan
context = sipnet-trunk
dtmf_mode = rfc4733
disallow = all
allow = alaw,ulaw
direct_media = no
from_user = логин
from_domain = sipnet.ru
outbound_auth=sipnet
aors = sipnet
 
[sipnet]
type = identify
endpoint = sipnet
match = sipnet.ru

;===============USER TEMPLATES
 
[endpoint-template](!)
type = endpoint
transport = transport-udp
context = homeoffice
dtmf_mode = rfc4733
disallow = all
allow = ulaw
allow = alaw
allow = g729
allow = g723
allow = g726
allow = h261
allow = h263
allow = h264
allow = h263p
 
[auth-template-userpass](!)
type = auth
auth_type = userpass
 
[aor-template-single-reg](!)
type = aor
; PjSIP допускает и множественные регистрации с одного аккаунта
max_contacts = 1

;===============User 1001

[1001](endpoint-template)
auth = auth1001
aors = 1001
callerid = Директор <1001>

[auth1001](auth-template-userpass)
username = 1001
password = пароль
 
[1001](aor-template-single-reg)

;===============User 1002

[1002](endpoint-template)
auth = auth1002
aors= 1002
callerid = Секретарь <1002>

[auth1002](auth-template-userpass)
username = 1002
password = пароль
 
[1002](aor-template-single-reg)


С шаблонами писанины стало меньше, но есть и более интересный способ упростить админу жизнь — Configuration Wizard. Пожалуй, это одна из самых удобных фишек PjSIP, с которой мы разберемся в следующей статье.

Переписываем Dialplan


Самая простая часть: достаточно заменить SIP на PJSIP в вызове приложения Dial. Пока мы немного изменили простейший тестовый Dialplan из предыдущей статьи, более сложными вещами займемся позднее.

Конфигурационный файл /etc/asterisk/extensions.conf
[general]
static=yes
writeprotect=no
priorityjumping=no
autofallthrough=yes
clearglobalvars=no

; Контекст по умолчанию принято закрывать ради удобства и безопасности
[default]
exten => _X.,1,NoOp()
same => n,Busy()
same => n,HangUp()

; Определяем контекст homeoffice
[homeoffice]
; разрешаем внутренние звонки
exten => _1XXX,1,Dial(PJSIP/${EXTEN})
; звонки по России производим через SIPNET
exten => _.7XXXXXXXXXX,1,Dial(PJSIP/${EXTEN:1}@sipnet)

; Определяем контекст sipnet-trunk, разрешаем входящие звонки через SIPNET
[sipnet-trunk]
; входящие звонки рассмотрим в следующей статье

Переход с chan_sip на PjSIP оказался делом не особенно сложным, но требующим изрядной доли ручной работы. Автоматически конвертировать конфигурацию у нас не получилось: сценарий выдал неработоспособный вариант, который пришлось переписать вручную. В следующей статье мы разберем работу с Configuration Wizard и наконец расширим dialplan для приема входящих вызовов, организации конференций и решения других задач маршрутизации звонков.



RUVDS.com
VDS/VPS-хостинг. Скидка 10% по коду HABR

Comments 7

    +1
    А какие преимущества на практике у PjSIP перед классическим SIP?
      +1
      chan_sip скоро не будет поддерживаться
        0
        Как минимум — нормальная поддержка Presence (BLF), расширяемая поддержка аутентификации, работа с несколькими! регистрациями на одном пире (несколько абонентских терминалов на одну учетную запись, позволяет работать с iOS с клиентов Zoiper/Bria), поддержка регистрации по username отличному от заголовка header и поля from.
        Отличий очень много, я бы сказал на целую статью потянет.
          +1
          PJSIP помог решить одну задачку.

          У меня один PBX, одна компания, но юридически — это разные компании. Стал вопрос о переводе одного из номеров на SIP. Сделали запрос провайдеру, оказалось, что у провайдера билинг привязан к IP клиента, и они не могут для разных компаний использовать один IP. В класической схеме Asterisk не предпологает более двух интерфейсов (LAN,WAN), соответственно при звонках в мир у меня в SIP светится основной IP asterisk и chan_sip не может ничего с этим сделать. А вот PJSIP позволяет указать разные sourсe IP для разных интерфейсов))
            0

            Из самого критичного что у меня было — сложность работы Астерикса с несколькими сетевыми интерфейсами, chan_sip позволяет слушать 5060 только на одном из интерфейсов, соответственно транк можно заводить только по одному айпишнику, намного сложнее настраивать разделения рег операторов и транков (к примеру чтобы операторы заводились на локальный интерфейс, а транки — на второй, куда внешка заведена), к тому же часто бывают причины, когда по юридическим причинам необходимо разные транки заводить по разным внешкам на один астериск — до этого приходилось пользоваться связкой с FreeSwitch как voip-маршрутизатором, а за ним уже ставился астериск, а chan_pjsip решает все эти вопросы.
            Да банально та же конфигурация — в chan_pjsip она намного гибче и функциональные нежели в chan_sip. Хотя chan_sip сильно проще, этого у него не отнять

            0
            название библиотеки «PJSIP» пишется полностью большими буквами
              +1
              а зачем раздувать конфиг если есть прекрасный механизм wizard? он как раз создан для упрощения конфигурации PJSIP

              wiki.asterisk.org/wiki/display/AST/PJSIP+Configuration+Wizard

              касаемо скриптов для трансформации — кто-то из разработчиков в презентации (к сожалению уже и не найду) говорил что использовать их стоит только для понимания как соотносятся конфиги SIP <-> PJSIP, не для продакшена

              Only users with full accounts can post comments. Log in, please.