📜 ⬆️ ⬇️

Auto-generation of Cisco phone configuration files

For companies using Cisco phones in the Asterisk environment, there is the problem of storing tens or hundreds of configuration files for each phone. In the wake of the need to update 30 phones (partly on firmware, partly on settings), I decided to offer a technology to automatically generate configuration files.

Immediately I must say that we are talking more about technology than about a specific implementation - the code is still raw and poorly debugged. This article assumes that you have already configured Cisco phones and are familiar with how they work, as suggested for example on voip-info.org and similar resources.

So, some setup data:

There are many kinds of tsyskofony, but here we are talking about phones using the Cisco Call Manager (CCM) technology and that’s all. Why it is so - they are the most pleasant to use from both the user and admin side.
')
The usual process of loading and working the phone from the moment it turns on looks like this:


The configuration file is quite large and complex, it defines almost all aspects of the phone, which causes some interest.

Suppose the TFTP server is our own software, then at the time of returning the configuration, the TFTP server could generate it if it knew the settings. In the minimum option, the list of parameters is as follows:


All this of course is in our catalogs except firmware.

1. Obtaining an IP Address


To find out what kind of firmware you need to offer - you also need to know the brand. Mark his phone says in two cases - in the field 60 of the DHCP request and during SIP registration. When registering, it is too late, so we will take the mark from the DHCP request.

In dhcpd.conf you can write the following:

on commit { set clip = binary-to-ascii(10, 8, ".", leased-address); set clhw = binary-to-ascii(16, 8, ":", substring(hardware, 1, 6)); execute("/root/bin/dhcpevent.php", "commit", clip, clhw, option vendor-class-identifier); } 

This will tell the DHCP server that when issuing a lease it calls a script of approximately the following form:

 /root/bin/dhcpevent.php commit 172.20.21.209 0:f:77:12:bc:aa "Cisco Systems, Inc. IP Phone CP-7945G" 

Here we need to save the brand somewhere in order to rely on it when requesting a configuration. You can store it anywhere - in the database, in the Asterisk database or a text file. I chose the option to store it in LDAP along with other credentials and use the unnecessary attribute telexNumber for this. To assign phones to people, I added the ieee802device class to them and assigned the macAddress attribute in the form of the phone's MAC address.

dhcpevent.php
 #!/usr/local/bin/php <?php $rdn = 'uid=root,ou=Users,dc=labma,dc=ru'; // DN to auth against LDAP $pass = 'superpass'; // Password $cont = "telexNumber"; // Attribute to fill with Cisco phone ID $ds = ldap_connect("pilot.labma.ru"); // Exit if not connected if (!$ds) exit (128); // Modern LDAP do not work on v1/v2 if (!ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3)) exit (128); // That means phone is not for us if (!preg_match ("/^Cisco/", $argv[4])) exit (1); $r = ldap_bind($ds, $rdn, $pass); $mac = ""; $macar = explode (":", $argv[3]); if (count($macar) != 6) exit (128); // PHP LDAP client get keys in low $contl = strtolower($cont); // DHCP server send not padded MAC foreach ($macar as $byte) $mac .= str_pad ($byte, 2, 0, STR_PAD_LEFT); $sr = ldap_search( $ds, "dc=labma, dc=ru", "macAddress=$mac", array ("dn", $cont) ); if (ldap_count_entries($ds, $sr) != 1) exit (4); $info = ldap_get_entries($ds, $sr)[0]; if ((array_key_exists($contl, $info)) && ($argv[4] == $info[$contl][0])) exit (0); $res = ldap_mod_replace ( $ds, $info["dn"], array ($cont => $argv[4]) ); if (!$res) exit (128); ldap_close ($ds); exit (0); ?> 

The script looks in the LDAP for a user with a MAC address, which is reported to dhcpd and gives him a telexNumber, if it has not yet been entered.

2. Getting configuration


Interestingly, tsiskofony first contact the TFTP server on port 6970, the HTTP protocol, and only then go as usual. I highly recommend replacing the TFTP server with HTTP / 6970 in my company - the phone download will speed up. Important! If the server responds, but returns 404 or 500, TFTP will not be requested and the phone will not boot. TFTP works fine if the 6970 does not respond at all. Worst of all, if the port is blocked - the download slows down at times.

Making VirtualHost *: 6970
 <VirtualHost *:6970> ServerAdmin webmaster@pbx.labma.ru DocumentRoot "/export/tftp" </VirtualHost> <Directory "/export/tftp/"> Options Indexes FollowSymLinks AllowOverride None Require ip 172.20.21.0/24 </Directory> 

and .htaccess:

 RewriteEngine On RewriteRule ^(.*)\.xml$ index.php [L] 


And in / export / tftp we put the actual index.php

 <?php if (preg_match ("/\SEP(\w+).cnf.xml/", $_SERVER["REQUEST_URI"], $m)) $mac = $m[1]; else { $file = getcwd ().$_SERVER["REQUEST_URI"]; if (!file_exists ($file)) _fail(); header ("Content-type: text/xml"); header ('Content-Length: ' . filesize($file)); readfile ($file); exit (0); } $user = _getUser($mac); if (!$user) _fail(); $tmpl = "template.".$user["cisco"].".xml"; if (!file_exists ($tmpl)) _fail (); $xml = file_get_contents ("template.".$user["cisco"].".xml"); // getLoadA hardcoded, loadB - search directory $user["load"] = _getLoadA($user["cisco"]); foreach ($user as $key => $value) { $xml = preg_replace ("/\#\#$key\#\#/m", $value, $xml); } header ("Content-type: text/xml"); header ('Content-Length: ' . strlen($xml)); echo $xml; exit; function _getUser ($mac) { $rdn = 'uid=root,ou=Users,dc=labma,dc=ru'; // DN to auth against LDAP $pass = 'superpassword'; // Password $cont = "telexNumber"; // Attribute to fill with Cisco phone ID $ds = ldap_connect("pilot.labma.ru"); // Exit if not connected if (!$ds) exit (128); // Modern LDAP do not work on v1/v2 if (!ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3)) exit (128); $r = ldap_bind($ds, $rdn, $pass); $sr = ldap_search( $ds, "dc=labma, dc=ru", "macAddress=$mac" ); if (ldap_count_entries($ds, $sr) != 1) { return null; } $info = ldap_get_entries($ds, $sr)[0]; $user = array(); $user ["label"] = $info["sn"][0]; $user ["phone"] = $info["uidnumber"][0]; if (preg_match ("/CP-(\d+)/", $info["telexnumber"][0], $m)) $user ["cisco"] = $m[1]; else return null; return $user; } function _getLoadA($cisco) { $list = array ( 3951 => "SIP3951.8-1-4a", 7906 => "SIP11.9-4-2SR1-1S", 7911 => "SIP11.9-4-2SR1-1S", 7931 => "SIP31.9-4-2SR2-2S", 7941 => "SIP41.9-4-2SR2-2S", 7945 => "SIP45.9-4-2SR2-2S", 7961 => "SIP41.9-4-2SR2-2S", 7965 => "SIP45.9-4-2SR2-2S", 8941 => "SIP894x.9-4-2SR3-1", 8845 => "sip8845_65.11-5-1SR1-1", 8865 => "sip8845_65.11-5-1SR1-1", ); if (!array_key_exists ($cisco, $list)) return ""; if (!file_exists (getcwd()."/".$list["cisco"].".loads")) return ""; return $list[$cisco]; } function _getLoadB($cisco) { $list = array ( 3951 => "SIP3951", 7906 => "SIP11", 7911 => "SIP11", 7931 => "SIP31", 7941 => "SIP41", 7945 => "SIP45", 7961 => "SIP41", 7965 => "SIP45", 8941 => "SIP894x", 8845 => "sip8845_65", 8865 => "sip8845_65", ); if (!array_key_exists ($cisco, $list)) return ""; $files = glob ($list[$cisco].".*.loads"); if (count($files) != 1) return ""; else return str_replace (".loads", "", $files[0]); } function _fail () { header ("HTTP/1.0 404 Not Found"); exit (0); } ?> 

Thus, the picture is as follows - the phone requests its SEP <MAC> file, rip out the MAC address from here, ask the LDAP for the brand and other parameters for the phone, open the template of the form template.7941.xml, change the variables in it and give it to the phone. If this is not an xml file, Apache will give it itself, if this is xml but not for us, we give it ourselves, if the poppy address or pattern is not found, call 404.

The function call _getLoadA can be replaced by _getLoadB and the firmware will be searched in the directory, in the first case, their names are statically inserted into the code.

Previously, I wanted to make complex templates out of common parts, and so on, but now I don’t see such a need for all phones except 3951 one template.

Now it is enough just to arrange the MAC addresses of the phones in the LDAP for users and that's it.

3. Hazards

Source: https://habr.com/ru/post/319450/


All Articles