Asterisk PJSIP wizard and phone provisioning
So after setting up Asterisk with a working DAHDI configuration for the PBX project, next was configuration for IP phones using PJSIP and provisioning them.
Asterisk has a built-in module called res_phoneprov which handles HTTP based phone provisioning but that didn’t work for me – I just couldn’t have it generate XML configuration for the phones that we had, i.e. Grandstream GXP1625.
The server on which I had configured PBX was multi-homed, as in it was part of multiple networks. But there was no reason to run the service on all interfaces except the VLAN on which we were going to connect the phones.
First, configuration for PJSIP transport:
; PJSIP configuration
; /etc/asterisk/pjsip.conf
[udp-phone]
type=transport
protocol=udp
bind=10.10.200.2:5060
Now one could do configuration of the phones in the above file itself, but configuring each phone involves very verbose configuration. Instead let’s use Asterisk’s PJSIP Wizard module. It simplifies the configuration by a large amount. The PJSIP wizard can configure the phoneprov module as well but as I stated above, I could never get that thing to work so I devised my own solution for that, especially since provisioning in my case just involved generating XML configuration files for the GXP1625 phones.
; /etc/asterisk/pjsip_wizard.conf
[user-template](!)
type = wizard
accepts_auth = yes
accepts_registrations = yes
endpoint/disallow = all
endpoint/allow = alaw,ulaw,gsm
aor/max_contacts = 2
endpoint/rewrite_contact = yes
endpoint/transport = udp-phone
That’s the wizard configuration initially, we define a user template which will be common to all phones.
Now add phone configuration to it:
[phone1](user-template)
inbound_auth/username = phone1
inbound_auth/password = phone1_password
endpoint/context = yourcontext
MAC = MAC Address of the phone
NAME = Display Name
The MAC and NAME parameters are used by a custom XML config generator script, more on that below.
In addition to the Grandstream phones, we had a single unit of Cisco 7940 which was bought for testing purpose, so configure that as well. But note that here, we need to add endpoint/force_rport = no otherwise the phone will not register with the server as discussed in this Asterisk forum post.
[phone2](user-template)
inbound_auth/username = phone2
inbound_auth/password = phone2_password
endpoint/context = yourcontext
endpoint/force_rport = no
Now some configuration for ISC DHCP Server so that the phones (both Grandstream, and Cisco) can find the provisioning server. Grandstream can use HTTP based provisioning method (documented by Grandstream in this PDF file) but for Cisco you need to use TFTP server. The configuration files are different for Cisco as well; further information on TFTP based provisioning for Cisco can be found here.
subnet 10.10.200.0 netmask 255.255.255.0 {
option routers 10.10.200.1;
option domain-name-servers 10.10.200.1;
range 10.10.200.3 10.10.200.254;
option tftp-server-name "http://10.10.200.2/gxp1625";
max-lease-time 1800;
}
host cisco_phone {
hardware ethernet xx:xx:xx:xx:xx:xx;
option tftp-server-name "10.10.200.2";
}
I wrote a simple PHP script to generate the XML configuration file for GXP1625:
<?php
if (strstr($_SERVER['REMOTE_ADDR'], '10.10.200.') === FALSE) {
header('Access Denied', true, 403);
exit;
}
$mac = $_REQUEST['mac'];
$configFile = file_get_contents('/etc/asterisk/pjsip_wizard.conf');
$iniFile = preg_replace('/\(.+\)/', '', $configFile);
$ini = parse_ini_string($iniFile, true);
foreach ($ini as $extname => $extconfig) {
if ($extconfig['MAC'] == $mac) {
$extension = $extname;
$username = $extconfig['inbound_auth/username'];
$password = $extconfig['inbound_auth/password'];
$display_name = $extconfig['NAME'];
break;
}
}
$xml = new SimpleXMLElement('<?xml version="1.0" encoding="UTF-8"?><gs_provision version="1"></gs_provision>');
$xml->addChild('mac', $mac);
$configXml = $xml->addChild('config');
$configXml->addAttribute('version', 1);
// account 1 active
$configXml->addChild('P271', 1);
// account name (display)
$configXml->addChild('P270', $display_name);
// sip server
$configXml->addChild('P47', '10.10.200.2');
// outbound proxy
$configXml->addChild('P48', '10.10.200.2');
// extension name
$configXml->addChild('P35', $extension);
// username
$configXml->addChild('P36', $username);
// password
$configXml->addChild('P34', $password);
// config lock type
$configXml->addChild('P1357', 2);
// disable firmware upgrade check
$configXml->addChild('P238', 2);
// user password
$configXml->addChild('P196', 'phone_user_password');
// admin password
$configXml->addChild('P2', 'phone_admin_password');
// disable ssh - WARNING NEGATIVE CONDITION
$configXml->addChild('P276', 0);
// PC VLAN ID
$configXml->addChild('P229', 3288);
header('Content-Type: text/xml');
print $xml->asXML();
Most of the Asterisk configuration files are valid INI files, but when we introduce templates into it the syntax of INI files becomes invalid, and PHP’s INI parser cannot read the file. So after reading the file I am doing a preg_replace in it to delete all text that contains round brackets, which is the way to use templates in the file.
All the parameter values written above, are not documented properly, so I found them out using the phone’s built-in web-interface and doing inspect-element on each form input field. There are a lot of other options but I haven’t added them to this file because they didn’t seem important.
And finally, a Nginx rewrite rule so that all requests for the cfgMAC.xml comes to our script with a mac= parameter.
rewrite ^/gxp1625/cfg([a-z0-9]+)\.xml$ /gxp1625.php?mac=$1;
Now you can configure your extensions.conf or extensions.lua as your prefer and do the testing if the phones are working correctly or not.
Hi,
Im having a problem making it work, I already have a apache server which I am currently using for another purposes (QPanel, and some html for my CRM).
I tried installing nginx as I am not using port 80 anyway, but after setting up everything I can see that the nginx is parsing the complete file without processing it via php.
I believe that’s happening because PHP is tied to apache so I decided to make it work kvia apache but I cannot make the rewrite rule to work. I lack some knowledge about HTTP Servers but tried to configure the RewriteRule inside .htaccess but I still cannot make it work.
Then I decided to make it work again through nginx but I am not sure how can I make it process PHP along with Apache. Is it possible?
Could you please help me on this?
here are my info on apache:
/etc/httpd/sites-available/gxp16xx.conf:
ServerName 10.0.2.50
RewriteEngine On
RewriteRule ^/gxp16xx/cfg([a-z0-9]+).xml$ /gxp16xx.php?mac=$1
ErrorLog /var/log/asterisk/phoneprov-error.log
CustomLog /var/log/asterisk/phoneprov-requests.log combined
.htaccess file:
RewriteEngine On
RewriteBase /
RewriteRule ^/gxp16xx/cfg([a-z0-9]+).xml$ /gxp16xx.php?mac=$1;
LikeLike
Actually your Apache configuration seems to be right. Are you able to generate the XML when you visit the cfg url?
Nginx or Apache both will work as long as you can setup that rewrite rule.
But since you said you were running Apache on some different port then you’ll have to configure the same in the DHCP server which is handing out leases to your phones. If you notice above I have specified http url in that option. Just append :port to that and it should start working. tcpdump is your friend.
LikeLike
when I go to 10.0.2.50/gxp16xx/cfg010101010101.xml it returns me a error:
“Not Found
The requested URL /gxp16xx/cfg010101010101.xml was not found on this server.”
How can I assure that the .htaccess is really working? Or should I put the RewriteRule inside the virtualhost configuration?
As i wasnt using port 80 earlier I mapped this phoneprov virtualhost on apache to port 80 just for simplicity.
LikeLike