Back to Home

Auto Generate Cisco Phone Configuration Files

asterisk · cisco 79xx · cisco 89xx

Auto Generate Cisco Phone Configuration Files

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

I must say right away that this is 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 is suggested for example on voip-info.org and similar resources.

So, some installation data:

There are many types of dialers, but here we are talking about phones using Cisco Call Manager (CCM) technology and more. Why exactly? They are the most pleasant to use both from the user and from the admin side.

The normal process of downloading and operating the phone from the moment it is turned on looks like this:

  • getting an IP address;
  • downloading a configuration file from a TFTP server (with the name of the form SEP.cnf.xml;
  • downloading various files mentioned in the configuration, incl. firmware;
  • Registration at Asterisk.

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

Suppose the TFTP server is our own software, then at the time the configuration was returned, the TFTP server could generate it if it knew the settings. In a minimal version, the list of parameters is as follows:

  • username / password of the device in Asterisk;
  • the name of the employee who has the phone;
  • phone firmware file name and phone brand, if the configurations are different.

All this of course is in our catalogs except for firmware.

1. Obtain an IP address


To find out what kind of firmware you need to offer, you also need to know the brand. The phone speaks its brand in two cases - in the DHCP request field 60 and when registering SIP. When registering, it is already late, so we will take the brand 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 to issue a script like this when lease is issued:

/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, so that when you request a configuration, we can rely on it. You can store it anywhere - in the database, in the Asterisk database or in a text file. I chose to store it in LDAP along with other credentials and use the unnecessary telexNumber attribute for this. To assign phones to people, I added the ieee802device class to them and attributed the macAddress attribute as the MAC address of the phone.

dhcpevent.php
#!/usr/local/bin/php
 $argv[4])
        );
if (!$res)
        exit (128);
ldap_close ($ds);
exit (0);
?>

The script looks in LDAP for the user with the mac address that dhcpd reported and telexNumber for it, if it is not already set.

2. Getting the configuration


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

Making VirtualHost *: 6970

    ServerAdmin [email protected]
    DocumentRoot "/export/tftp"

    Options Indexes FollowSymLinks
    AllowOverride None
    Require ip 172.20.21.0/24

and .htaccess:

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


And in / export / tftp we put actually index.php

 $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 asks for its SEP file, we tear out the poppy address from here, ask the LDAP brand and other parameters for the phone, open a template of the form template.7941.xml, change the variables in it and give it to the phone. If it is not xml - Apache itself will give the file, if it is xml but not for us - we give it ourselves, if the poppy address or template is not found - by phone 404.

You can replace the _getLoadA function call with _getLoadB and the firmware itself will be searched in the directory, in the first in the case of their names are statically driven into the code.

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

Now it’s enough to simply set up the MAC addresses of phones in LDAP users and that’s it.

3. Hazards

  • If port 6970 answers clearly - TFTP will not be requested
  • Phones with SIP 8.x firmware do not request port 6970
  • TCP and UDP phones cannot work in the same Asterisk at the same time - keep an eye on the firmware and the transportLayer tag
  • DHCP server sends poppy without insignificant zeros
  • LDAP server searches for MAC case insensitive

Read Next