Автопровижининг Cisco SPA504g и Asterisk. Часть 2. Настройка DHCP-сервера и Apache

в 13:41, , рубрики: asterisk, Cisco, ip-телефония, linux, provisoning, телефония, метки: , , ,

В первой части мы установили MySQL и собрали Астериск из исходников с поддержкой res_config_mysql (Asterisk Realtime Architecture)

Настройка DHCP-сервера

У меня в двух рабочих средах развёрнуты разные DHCP-серверы, покажу настройки для трёх самых (имхо) популярных: Windows Server DHCP, Mikrotik, DNSMasq

Windows Server 2012R2 DHCP Server

image

В DHCP-менеджере добавляем новую опцию к нашему DHCP-диапазону, с номером 66 (Boot Server Host Name) и следующим содержимым
http://<server ip>/cisco.php?mac=$MA&sn=$SN

Mikrotik RouterOS v6.x

/ip dhcp-server option
add code=66 name=tftp value="'http://<server ip>/cisco.php?mac=$MA&sn=$SN'"
/ip dhcp-server network
set dhcp-option=tftp 0

DNSMasq

в dnsmasq.conf
dhcp-option=66,"http://<server ip>/cisco.php?mac=$MA&sn=$SN"

Установка и настройка Apache + PHP

Можно было обойтись и thttpd, и lighttpd, и даже nginx'ом, но я больше люблю старого доброго индейца.

[root@asterisk ~]# yum install httpd php php-mysql -y
[root@asterisk ~]# chkconfig httpd on
[root@asterisk ~]# vi /etc/php.ini

и в разделе Date устанавливаем date.timezone = Europe/Moscow (или свою временную зону, если не в Московском часовом поясе), иначе будет куча предупреждений.

Esc -> :wq -> Enter
[root@asterisk ~]# echo "<?php phpinfo(); ?>">/var/www/html/index.php

И открываем браузером адрес http://<ip сервера>/ для проверки работы Апача и PHP.

Создаём скрипт автовыдачи XML для SPA504G

Скачиваем и распаковываем в /var/www/html прошивки 7.5.2b и 7.5.5 для SPA504G, а также языковые XML'ки для русского языка:

[root@asterisk ~]# cd /var/www/html/
[root@asterisk html]# wget http://zztopper.ru/cisco.tar.gz
[root@asterisk html]# tar fzx cisco.tar.gz
[root@asterisk html]# rm cisco.tar.gz

Создаём cisco.php

[root@asterisk html]#  nano cisco.php

<?php

//---------------------------------Тут объявляем переменные

//-------Данные MySQL
$mysrv = 'localhost';
$mydb = 'asterisk';
$myuser = 'asterisk';
$mypass = 'mypass';
$table = 'tbl_sip_conf';

$server = 'SERVERIP'; //IP сервера с апачем и астериском
$dns = 'DNSIP';  // IP DNS-сервера
$enable_vlan = 'No'; // Использовать VLAN'ы
$voice_vlan = 1; // VLAN для телефонии 
$pc_vlan = 1; // Access VLAN для сквозного PC-порта
$adminpass = '7654321'; //Пароль для Web-морды телефона
$textlogo = 'LOGO'; //Текстовое лого 
$tz = 'GMT+04:00'; //Часовой пояс
$dialplan = '(1xxS0|911S0|1xxxS0|2xxxxxxS0|8xxxxxxxxxx|7xxxxxxxxxx)'; //Строка диалплана
$label = 'Yellow Pages'; //Подпись для кнопки Line 4 для адресной книги
$use4line = 1; // Использовать ли кнопку Line 4 для адресной книги
//---------------------------------Дальше сам скрипт, не трогаем без нужды

function randomPassword() {
    $alphabet = "abcdefghijklmnopqrstuwxyzABCDEFGHIJKLMNOPQRSTUWXYZ0123456789";
    $pass = array(); //remember to declare $pass as an array
    $alphaLength = strlen($alphabet) - 1; //put the length -1 in cache
    for ($i = 0; $i < 10; $i++) {
        $n = rand(0, $alphaLength);
        $pass[] = $alphabet[$n];
    }
    return implode($pass); //turn the array into a string
}

 $mac = isset($_GET['mac'])?$_GET['mac']:"000000000000";
 $sn = isset($_GET['sn'])?$_GET['sn']:"0000000";
 $link = new mysqli($mysrv,$myuser,$mypass,$mydb);
if ($link->connect_error) {
    die('Connect Error (' . $link->connect_errno . ') '
            . $link->connect_error);
}
 $query = 'set names utf8;';
 $link->query($query);
 $query = 'SELECT * FROM `'.$table.'` WHERE `macaddress`="'.$mac.'"';
 $result = $link->query($query);
 if (!$result).
    die("Ошибка: ".$link->error);
 if ($result->num_rows == 1).
 {
    while ($myrow = $result->fetch_array(MYSQLI_ASSOC))
    {
      $phone=$myrow["name"];
      $pass=$myrow["secret"];
      $name=$myrow["defaultuser"];
    }.
    $result->close();.
 }else
 {
 $query="SELECT MAX(name) FROM `".$table."`";
 $result = $link->query($query);
 while ($myrow = $result->fetch_array(MYSQLI_NUM))
 {
    $phone=$myrow[0];
 }
    $phone++;
 $result->close();                                                                                                $pass=randomPassword();   
 $name="Unidentified Phone #".$phone;
 $query="INSERT INTO `".$table."` (`defaultuser`,`macaddress`,`secret`,`name`, `serial`) VALUES ('".$name."', '".$mac."', '".$pass."', '".$phone."', '".$sn."');";
 $result=$link->query($query);
 }
 $host="SPA".strtoupper($mac);
?>
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<flat-profile xmlns="http://www.sipura.net/xsd/SPA50x-30x-SIP" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sipura.net/xsd/SPA5
<Enable_VLAN ua="rw"><?php echo $use_vlan ?></Enable_VLAN>
<VLAN_ID ua="rw"><?php echo $voice_vlan?></VLAN_ID>
<Enable_PC_Port_VLAN_Tagging ua="na">No</Enable_PC_Port_VLAN_Tagging>
<Enable_CDP ua="na">Yes</Enable_CDP>
<Enable_LLDP-MED ua="na">Yes</Enable_LLDP-MED>
<PC_Port_VLAN_ID ua="na"><?php echo $pc_vlan ?></PC_Port_VLAN_ID>
<Resync_On_Reset>Yes</Resync_On_Reset>
<Resync_Periodic>60</Resync_Periodic>
<Admin_Passwd ua="na"><?php echo $adminpass ?></Admin_Passwd>
<SPCP_Auto-detect ua="na">No</SPCP_Auto-detect>
<Domain ua="rw">aton.local</Domain>
<Primary_DNS ua="rw">$dns</Primary_DNS>
<Debug_Level ua="na">0</Debug_Level>
<Primary_NTP_Server ua="na">ru.pool.ntp.org</Primary_NTP_Server>
<Profile_Rule ua="na">http://<?php echo $server?>/cisco.php?mac=$MA&sn=$SN</Profile_Rule>
<Key_System_Auto_Discovery ua="na">No</Key_System_Auto_Discovery>
<G722_Enable_1_ ua="na">Yes</G722_Enable_1_>
<L16_Enable_1_ ua="na">No</L16_Enable_1_>
<G726-16_Enable_1_ ua="na">No</G726-16_Enable_1_>
<G726-24_Enable_1_ ua="na">No</G726-24_Enable_1_>
<G726-32_Enable_1_ ua="na">No</G726-32_Enable_1_>
<G726-40_Enable_1_ ua="na">No</G726-40_Enable_1_>
<Enable_IP_Dialing_1_ ua="na">No</Enable_IP_Dialing_1_>
<Use_Remote_Pref_Codec_1_ ua="na">Yes</Use_Remote_Pref_Codec_1_>
<Text_Logo ua="na"><?php echo $textlogo ?></Text_Logo>
<Time_Zone ua="na"><?php echo $tz ?></Time_Zone>
<Upgrade_Rule ua="na">( $SWVER lt 7.5.2b )? http://<?php echo $server ?>/spa50x-30x-7-5-2b.bin | http://<?php echo $server ?>/spa50x-30x-7-5-5.bin </Upgrade_Rule>
<HostName ua="rw"><?php echo $host ?></HostName>
<Phone-UI-readonly ua="na">Yes</Phone-UI-readonly>
<Phone-UI-user-mode ua="na">Yes</Phone-UI-user-mode>
<Proxy_1_ ua="na"><?php echo $server ?></Proxy_1_>
<Display_Name_1_ ua="na"><?php echo $name ?></Display_Name_1_>
<User_ID_1_ ua="na"><?php echo $phone ?></User_ID_1_>
<Password_1_ ua="na"><?php echo $pass ?></Password_1_>
<Dial_Plan_1_ ua="na"><?php echo $dialplan ?></Dial_Plan_1_>
<Station_Name ua="na"><?php echo $phone ?></Station_Name>
<Date_Format>day/month</Date_Format>                                                                             
<Time_Format ua="rw">24hr</Time_Format>         
<Station_Display_Name ua="na"><?php echo $name ?></Station_Display_Name>
<Server_Type ua="na">Asterisk</Server_Type>
<Language_Selection ua="na">Russian</Language_Selection>
<Dictionary_Server_Script ua="na">serv=http://<?php echo $server?>/;d0=English;x0=spa50x_30x_en_v755.xml;d1=Russian;x1=spa50x_30x_ru_v755.xml</Dictionary_Server_Script>
<Default_Character_Encoding ua="na">UTF-8</Default_Character_Encoding>
<Locale ua="na">ru-RU</Locale>
<!-- Vertical Service Activation Codes -->
<Call_Return_Code ua="na"></Call_Return_Code>
<Blind_Transfer_Code ua="na"></Blind_Transfer_Code>
<Call_Back_Act_Code ua="na"></Call_Back_Act_Code>
<Call_Back_Deact_Code ua="na"></Call_Back_Deact_Code>
<Cfwd_All_Act_Code ua="na"></Cfwd_All_Act_Code>
<Cfwd_All_Deact_Code ua="na"></Cfwd_All_Deact_Code>
<Cfwd_Busy_Act_Code ua="na"></Cfwd_Busy_Act_Code>
<Cfwd_Busy_Deact_Code ua="na"></Cfwd_Busy_Deact_Code>
<Cfwd_No_Ans_Act_Code ua="na"></Cfwd_No_Ans_Act_Code>
<Cfwd_No_Ans_Deact_Code ua="na"></Cfwd_No_Ans_Deact_Code>
<CW_Act_Code ua="na"></CW_Act_Code>
<CW_Deact_Code ua="na"></CW_Deact_Code>
<CW_Per_Call_Act_Code ua="na"></CW_Per_Call_Act_Code>
<CW_Per_Call_Deact_Code ua="na"></CW_Per_Call_Deact_Code>
<Block_CID_Act_Code ua="na"></Block_CID_Act_Code>
<Block_CID_Deact_Code ua="na"></Block_CID_Deact_Code>
<Block_CID_Per_Call_Act_Code ua="na"></Block_CID_Per_Call_Act_Code>
<Block_CID_Per_Call_Deact_Code ua="na"></Block_CID_Per_Call_Deact_Code>
<Block_ANC_Act_Code ua="na"></Block_ANC_Act_Code>
<Block_ANC_Deact_Code ua="na"></Block_ANC_Deact_Code>
<DND_Act_Code ua="na"></DND_Act_Code>
<DND_Deact_Code ua="na"></DND_Deact_Code>
<Secure_All_Call_Act_Code ua="na"></Secure_All_Call_Act_Code>
<Secure_No_Call_Act_Code ua="na"></Secure_No_Call_Act_Code>
<Secure_One_Call_Act_Code ua="na"></Secure_One_Call_Act_Code>
<Secure_One_Call_Deact_Code ua="na"></Secure_One_Call_Deact_Code>
<Paging_Code ua="na"></Paging_Code>
<Call_Park_Code ua="na"></Call_Park_Code>
<Call_Pickup_Code ua="na"></Call_Pickup_Code>
<Call_UnPark_Code ua="na"></Call_UnPark_Code>
<Group_Call_Pickup_Code ua="na"></Group_Call_Pickup_Code>
<Media_Loopback_Code ua="na"></Media_Loopback_Code>
<Referral_Services_Codes ua="na"></Referral_Services_Codes>
<Feature_Dial_Services_Codes ua="na"></Feature_Dial_Services_Codes>
<XML_Directory_Service_Name ua="na">Address Book</XML_Directory_Service_Name>
<XML_Directory_Service_URL ua="na">http://<?php echo $server ?>/directory.php</XML_Directory_Service_URL>
<?php
if ($use4line==1){ ?>
<Extension_4_ group="Phone/Line_Key_4">Disabled</Extension_4_>
<Short_Name_4_ group="Phone/Line_Key_4"><?php echo $label ?></Short_Name_4_>
<Share_Call_Appearance_4_ group="Phone/Line_Key_4">private</Share_Call_Appearance_4_>   
<Extended_Function_4_ group="Phone/Line_Key_4">fnc=xml;url=http://<?php echo $server ?>/directory.php</Extended_Function_4_>
<?php } ?>
</flat-profile>

Тут же сделаем PHP-файл для адресной книги:

nano directory.php

<?php

//-------Данные MySQL
$mysrv = 'localhost';
$mydb = 'asterisk';
$myuser = 'asterisk';
$mypass = 'mypass';
$table = 'tbl_sip_conf';

$mysqli = new mysqli($mysrv,$myuser,$mypass,$mydb);
if ($mysqli->connect_error) {
    die('Connect Error (' . $mysqli->connect_errno . ') ' . $mysqli->connect_error);
}
$mysqli->query("set names utf8");
$query = 'SELECT * from `'.$table.'` ORDER BY `defaultuser` ASC';
$result=$mysqli->query($query);
while ($row = $result->fetch_assoc()){
$phones[] = $row['name'];
$names[] = $row['defaultuser'];
}
$mysqli->close();

?>
<?xml version="1.0" encoding="utf-8" ?>
<CiscoIPPhoneDirectory>
   <Title>Каталог</Title>
   <Prompt>Выберите номер</Prompt>
<?php
foreach($phones as $k=>$v){?>
   <DirectoryEntry>
     <Name><?php echo $names[$k]." - ".$v;?></Name>
     <Telephone><?php echo $v;?></Telephone>
   </DirectoryEntry>
<?php
}
?>
</CiscoIPPhoneDirectory>

Кратко подытожим

Таким образом, у нас сейчас телефон при подключении к сети получает IP-адрес и DHCP-опцию 66 от DHCP-сервера, после чего идёт на адрес, указанный в опции 66, за персональным конфигом. Если версия его прошивки меньше, чем 7.5.2b, то он обновляется на неё, если нет — то на 7.5.5 (актуальная в момент написания поста).
После чего пытается регистрироваться на сервере Астериска с логином-паролем из БД.
Если в БД ранее телефон с этим MAC-адресом не появлялся — создаётся запись «Unidentified phone #xxxx', и телефон так же регистрируется на Астериске с этой записью.

Еще на четвёртую кнопку выбора линии я повесил вызов XML-каталога с адресной книгой, каковую скрипт сгенерит на лету прямо из таблицы пиров в БД.

В третьей части мы накидаем простенький веб-интерфейс для редактирования/создания/удаления номеров из таблицы.

Комментарии и пожелания — велком, очень жду!

Автор: ZZToP

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js