Как стать автором
Обновить

Askozia. Как работает Autoprovisioning Plug & Play

Open source **nix *Asterisk *Разработка систем связи *
При разработке АТС Askozia мы столкнулись с задачей по автоматической настройке телефонов и решили ее по-своему.

Autoprovisioning Plug & Play (PnP), эту технологию поддерживают многие производители — Yealink, Snom, Fanvil.

Основные достоинства автоматической настройки телефонов:

  • Облегчает первичную настройку — не требуется заходить в web интерфейс каждого устройства. Достаточно на сервере автонастройки указать соответствие MAC адреса устройства и акканута.
  • Упрощает поддержку — действительно становится легче при необходимости изменить настройки устройства. Управляем настройками опять же на сервере
  • Возможно свести настройку к набору старкода «*911*<SIP_ACC>» — в ряде случаев этой функции просто цены нет. Не каждый офисный работник сможет настроить IP телефон, а вот набрать комбинацию цифр задача простая.

Опишем как же работает Autoprovisioning Plug & Play. В конце статьи ссылка на исходники небольшого PHP скрипта, реализующего функционал PnP сервера.

Пример из опыта


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

Решена задача была относительно просто. Клиент зарезервировал для нас ряд IP адресов. Мы настроили оборудование у себя в офисе и упаковав в коробку выслали курьерской службой.

При использовании автоматической настройки аппаратов задача стала бы намного проще.

Упрощенная схема работы PnP


Телефонный аппарат при начале работы отправляет широковещательный SIP запрос SUBSCRIBE на адрес 224.0.1.75 multicast IP.
Подробнее о 224.0.1.75
224.0.1.75 — это multicast IP (для многоадресной рассылки) «зарезервирован» для SIP серверов.
см. networksorcery.com/Enp/protocol/sip.htm
224.0.1.75 SIP, Session Initiation Protocol (all servers).

В ответ ожидает получить ответ NOTIFY с инструкциями по настройке.

image

Пример SUBSCRIBE
2019/09/02 09:26:41.543856 172.16.32.148:5059 -> 224.0.1.75:5060
SUBSCRIBE sip:MAC0015657322ff@224.0.1.75 SIP/2.0
Via: SIP/2.0/UDP 172.16.32.148:5059;branch=z9hG4bK42032775
From: <sip:MAC0015657322ff@224.0.1.75>;tag=42032772
To: <sip:MAC0015657322ff@224.0.1.75>
Call-ID: 42032772@172.16.32.148
CSeq: 1 SUBSCRIBE
Contact: <sip:MAC0015657322ff@172.16.32.148:5059>
Max-Forwards: 70
User-Agent: Yealink SIP-T21P 34.72.14.6
Expires: 0
Event: ua-profile;profile-type="device";vendor="Yealink";model="T21D";version="34.72.14.6"
Accept: application/url
Content-Length: 0


Наиболее важные и интересные заголовки


  • From — передается мак адрес устройства 0015657322ff
  • Event — исчерпывающе описывает устройство, Производитель, модель, версия прошивки
  • Contact — адрес устройства
  • Call-ID — этот заголовок интересен при настройке DECT устройств от Yealink, в нем передается идентификатор линии (порядковый номер трубки), разделитель "_"

Как только сервер PnP получил такой запрос, он должен ответить

Пример NOTIFY
2019/09/02 09:26:41.550125 172.16.32.153:57593 -> 172.16.32.148:5059
NOTIFY sip:172.16.32.148:5059 SIP/2.0
Via: SIP/2.0/UDP 172.16.32.148:5059;branch=z9hG4bK42032775
Max-Forwards: 20
Contact: <sip:172.16.32.148:5059;transport=UDP;handler=dum>
From: <sip:MAC0015657322ff@224.0.1.75>;tag=42032772
To: <sip:MAC0015657322ff@224.0.1.75>
Call-ID: 42032772@172.16.32.148
CSeq: 3 NOTIFY
Content-Type: application/url
Subscription-State: terminated;reason=timeout
Event: ua-profile;profile-type="device";vendor="MIKO";model="MikoServerPnP";version="1.8"
Content-Length: 40

http://172.16.32.153:84/0015657322ff.cfg


В NOTIFY сообщении наиболее ценная информация находится в теле сообщения. Как правило, в теле необходимо передать ссылку на получение конфигурационного файла:

http://172.16.32.153:84/0015657322ff.cfg

Если в сети работает несколько PnP серверов, то кто первый кто ответит устройству, будет его настраивать.

Телефон при получении NOTIFY пытается выполнить запрос по указанному адресу.

Пример запроса и ответа сервера
# curl -i http://172.16.32.153:84/0015657322ff.cfg
HTTP/1.0 200 OK
Content-type: text/plain
Date: Mon, 02 Sep 2019 06:52:23 GMT
Connection: close
Accept-Ranges: bytes
Last-Modified: Mon, 02 Sep 2019 06:25:02 GMT
Content-length: 769

#!version:1.0.0.1
account.1.enable = 1
account.1.label = PnP (203)
...


Пример реализации сервера доступен на github https://github.com/boffart/MikoServerPnP

Для работы этого сервера PnP необходимо:

  • PHP 7.1.9
  • PHP sockets
  • BusyBox v1.26.2
  • В сети должны быть разрешены широковещательные запросы

Возможности сервера PnP


  • Слушает запросы, отправленные на адрес ‘224.0.1.75:5060
  • При начале работы запускает web серевер (busybox httpd)
  • Позволяет создать упрощенный конфиг телефона
  • Позволяет отправить на Yealink NOTIFY для перезагрузки

Использование PnP сервера позволяет использовать «Одноразовые ссылки».


Допустим мы отдаем файл по ссылке:

http://172.16.32.153:84/0015657322ff.cfg

Обычная прямая ссылка на файл. Очевидно, что это НЕ безопасно. Зная MAC адрес телефона и адрес сервера можно попробовать получить конфиг с логинами и паролями.

При работе с PnP сервером возможно для каждого SUBSCRIBE запроса отдавать уникальную ссылку:

http://172.16.32.153:84/?mac=0015657322ff&hash=0a67f5290

Пример формулы для расчета хэш:

hash = md5(MAC + DATE + PID)

PID — это ID процесса PnP сервера. Его узнать может только root.
Подобрать такой hash практически не реально.

Если происходит обращение по недействительной ссылке, то баним вредителя.

Reboot Yealink средствами NOTIFY без авторизации


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

Достаточно выполнить команду

php -f MikoServerPnP.php socket_client_notify <IP_PBX> <PORT_SIP_PBX> <IP_PHONE> <PORT_PHONE>

И телефон уйдет в ребут. Повесив такую команду в cron можно добиться ужасающего эффекта. Конечно это возможно если мы знаем IP адрес и SIP порт телефона.

Пример PHP функции на отправку NOTIFY
    public static function socket_client_notify($ip_pbx, $port_pbx, $ip_phone, $port_phone):void {
        $phone_user = 'autoprovision_user';
        $sock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
        $msg =  "NOTIFY sip:{$phone_user}@{$ip_phone}:{$port_phone};ob SIP/2.0\r\n".
            "Via: SIP/2.0/UDP {$ip_pbx}:{$port_pbx};branch=z9hG4bK12fd4e5c;rport\r\n".
            "Max-Forwards: 70\r\n".
            "From: \"asterisk\" <sip:asterisk@{$ip_pbx}>;tag=as54cd2be9\r\n".
            "To: <sip:{$phone_user}@{$ip_phone}:{$port_phone};ob>\r\n".
            "Contact: <sip:asterisk@{$ip_pbx}:{$port_pbx}>\r\n".
            "Call-ID: 4afab6ce2bff0be11a4af41064340242@{$ip_pbx}:{$port_pbx}\r\n".
            "CSeq: 102 NOTIFY\r\n".
            "User-Agent: mikopbx\r\n".
            "Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, SUBSCRIBE, NOTIFY, INFO, PUBLISH, MESSAGE\r\n".
            "Supported: replaces, timer\r\n".
            "Subscription-State: terminated\r\n".
            "Event: check-sync;reboot=true\r\n".
            "Content-Length: 0\r\n\n";
        $len = strlen($msg);
        socket_sendto($sock, $msg, $len, 0, $ip_phone, $port_phone);
        socket_close($sock);
    }


Настройка сервера PnP


Располагаются в settings/settings.json

{
  "url": "http://<pbx_host>:<http_port>/",
  "http_port": 84,
  "pbx_host": "172.16.32.153",
  "pbx_sip_port": "5060",
  "vm_extension": "*001",
  "feature_transfer": "**"
}

Белый список MAC


Можно описать в settings/mac_white.conf. Разделитель — перевод строки.

Черный список MAC


Можно описать в settings/mac_black.conf. Разделитель — перевод строки.

Конфигурационные файлы телефонов


Необходимо поместить в каталог configs.
Средствами PnP сервера есть возможность создать простейшие конфиги для Yeakink и Snom:

php -f MikoServerPnP.php mk_config SIP_ACCAUNT SECRET MAC

Полезные материалы


Теги:
Хабы:
Всего голосов 9: ↑8 и ↓1 +7
Просмотры 3.2K
Комментарии Комментарии 4