Подключаем телефоны 20.04.2011

Настало время подключить телефоны к астериск по протоколу SIP и сделать «звонок другу» :)

Выбор протокола

Asterisk поддерживает большое количество протоколов для работы. На данный момент, имеет смысл остановится только на двух из них – SIP и IAX2. Какой протокол выбрать для стационарных IP телефонов - решать, разумеется, вам.

В моем случае, для телефонов внутри локальной сети выбран SIP, т.к. это устоявшийся протокол, поддерживается всеми производителями, шустрый и тд. К его недостатком можно отнести его сложность при работе через NAT.

В то же время, для подключения к внешним сетям и «межастерисковой» связи, на мой взгляд, уместнее использовать IAX2. IAX2 расшифровывается как (если не ошибаюсь) Inter Asterisk eXchange, и я не вижу смысла не использовать его для связи с внешними источниками, т.к. он легко проходит NAT, не требует открытия большого количества портов (точнее, требует только один UDP) и как бы специально для этого и предназначен.

Файл sip.conf

В астериск существует два пути подключения пользователей – через файл users.conf, который является общим для всего астериска или через выделенные файлы – sip.conf и iax.conf – соответственно, для протоколов SIP и IAX2.

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

Файл sip.conf (как и большинство других конфигурационных файлов asterisk) состоит из секции [general], в которой перечисляются параметры для всех подключенных устройств, и индивидуальных настроек для каждого устройства.

В раздел [general] я решил для начала внести минимум настроек.

[general]
context=internal_phones ; Этот контекст будет использоваться
                        ; для звонков с/на внутренние телефоны

allowoverlap=no         ; Насколько я понял, это отключение набора
                        ; по мере поступления номера, т.е.
                        ; система будет ждать полного номера
                        ; и лишь затем начнет набирать.

bindport=5060           ; управляющий SIP порт. Это значение по-
                        ; умолчанию

srvlookup=no            ; эта функция позволяет набирать номер
                        ; по доменному имени пользователя
                        ; я ее отключил от греха подальше.

qualify=200             ; если ответ от телефона идет более,
                        ; чем 0.2 секунды - считаем его
                        ; неработающим.

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

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

В случае открытой системы обязательно наложите ограничение на пул IP, установите пароли посложнее, пропишите правила на фаерволе!

[1260]          ; это мой телефон. звоните :)

type=friend     ; пользователь может и принимать
                ; звонки, и звонить

host=dynamic    ; т.к. телефоны получают IP по
                ; DHCP, то нужно поставить значение dynamic

username=1260   ; мы решили использовать имя пользователя,
                ; совпадающее с его номером - так немного проще

secret=****     ; пароль для подключения телефона. На данном
                ; этапе, все пароли будут одинаковыми.
                ; потом мы это поменяем.

[1261]          ; а это - второй телефон
type=friend
host=dynamic
username=1261
secret=****    

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

Перезагружаем конфигурацию SIP и смотрим на результат.

asterisk*CLI> sip reload
asterisk*CLI> sip show users
Username                   Secret           Accountcode      Def.Context      ACL  ForcerPort
1260                       ****                   internal_phones  No   No
1261                       ****                   internal_phones  No   No

Теоретически, настроенные телефоны должны сразу подключиться к астериск.

На практике, в моем случае это не произошло, т.к. после установки CentOS по-умолчанию закрыты все порты.

Необходимо разрешить входящие TCP и UDP на порт 5060, а так же входящие UDP на интервал 10000-20000. Я, на всякий случай, прописал еще и ограничение по исходному IP.

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

asterisk*CLI> sip show peers
Name/username              Host                                    Dyn Forcerport ACL Port     Status
1260/1260                  10.62.20.240                             D          5060     OK (5 ms)
1261/1261                  10.62.20.238                             D          5060     OK (5 ms)
2 sip peers [Monitored: 2 online, 0 offline Unmonitored: 0 online, 0 offline]

Оба телефона, как нетрудно заметить, подключены.

Разумеется, в этот момент крайне хочется на одном из телефонов набрать номер другого, услышать голос коллеги (или свой же) и несколько секунд с идиотской улыбкой на лице «аллекать».

Набираем номер, но не тут-то было – в телефоне короткие гудки. Разумеется, если телефон не подключен, то его реакция объяснима. Но наш-то подключен :)

Проблема кроется в том, что у нас пустой диалплан. Соответственно, звонок уходит в «тупик», и телефон дает отбой.

Это можно увидеть через консоль. Подключаемся, набираем номер и видим:

[2011-04-14 17:50:12] NOTICE[6329]: chan_sip.c:21358 handle_request_invite: Call from '1260' to extension '1261' rejected because extension not found in context 'internal_phones'.

Простейший диалплан

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

Итак, нашу текущую задачу можно описать так: При наборе четырехзначного номера – набрать его через SIP.

Создаем файл extensions.conf и в нем прописываем

[globals]

[general]

[default]   ; контекст для звонков без заданного контекста
            ; обычно это входящие звонки
; Ругнемся в лог
exten => s,1,Verbose(Hey! WTF??? ${EXTEN} dialed from default!)
; и повесим трубку
exten => s,n,Hangup()              

[internal_phones]
; все следующие правила будут работать при наборе любого номера из четырех цифр

; вывод сообщения в консоль
exten => _XXXX,1,Verbose(Test call 4 digits)
; выведем номер, который мы набираем
exten => _XXXX,n,Verbose(Dialed number:${EXTEN})
; наберем его через SIP, используя переменную
; EXTEN
exten => _XXXX,n,Dial(SIP/${EXTEN})
; в конце - повесим трубку
exten => _XXXX,n,Hangup()

Перезагрузим диалплан и сделаем звонок.

asterisk*CLI> dialplan reload
Dialplan reloaded.
  == Using SIP RTP CoS mark 5
    -- Executing [1261@internal_phones:1] Verbose("SIP/1260-00000007", "Test call 4 digits") in new stack
Test call 4 digits
    -- Executing [1261@internal_phones:2] Verbose("SIP/1260-00000007", "Dialed number:1261") in new stack
Dialed number:1261
    -- Executing [1261@internal_phones:3] Dial("SIP/1260-00000007", "SIP/1261") in new stack
  == Using SIP RTP CoS mark 5
    -- Called 1261
    -- SIP/1261-00000008 is ringing
    -- SIP/1261-00000008 answered SIP/1260-00000007
    -- Remotely bridging SIP/1260-00000007 and SIP/1261-00000008
  == Spawn extension (internal_phones, 1261, 3) exited non-zero on 'SIP/1260-00000007'

Другой телефон звонит и можно поговорить.

В следующей статье я планирую описать (и узнать :) – как расширить диалплан, чтобы фиксировать звонки по несуществующим номерам и выдавать какое-нибудь приятное голосовое сообщение.