Monthly Archives: August 2011

If your Linux-based PC with NVIDIA graphics started booting to a black screen or text only, here is the fix — maybe!

 

Important
This is an edited version of a post that originally appeared on a blog called The Michigan Telephone Blog, which was written by a friend before he decided to stop blogging. It is reposted with his permission. Comments dated before the year 2013 were originally posted to his blog.
Image representing NVidia as depicted in Crunc...

Image via CrunchBase

I’ve seen this happen several times now on Ubuntu-Linux based systems that have NVIDIA graphics.  What happens is that “Update Manager” pops up and tell you there are updates for your software, and you accept them.  It then tells you that your system has to be rebooted.  And when you do that, you get no video, or text only.  What probably happened was that the updates you installed included an update to the Linux kernel, and the NVIDIA graphics driver currently installed on the system was compiled against the OLD kernel.

Note that this generally can only happen if you manually updated the NVIDIA graphics driver at some point. If you always installed it from the standard repositories for your distribution, you’ll probably never see this issue. So a word to the wise — when you finally get around to doing an upgrade of your Linux distribution, try to avoid manually installing the NVIDIA graphics driver. Instead, let the distribution pull it from its repository. After that, you should not have this issue in the future. By the way, if you currently are running Ubuntu, we recommend upgrading to Linux Mint rather than a newer version of Ubuntu. Linux Mint is very similar to Ubuntu, but leaves out some of the things that users seem to hate about newer releases of Ubuntu. More to the point, they are not currently talking about switching their base graphics system from the X window server system to a new display manager, which I have a feeling might cause problems for some NVIDIA graphics users.

But if you’re not yet ready to do a full reinstall of Linux, the fix for this problem is easy IF you had the foresight to set up SSH access to your Linux system BEFORE the trouble started.  If you didn’t, and you’re not a true Linux geek, you may be kind of screwed.  So if you’re reading this and your system is working fine, and you haven’t yet set up SSH access, you may want to do that.  There are several sites that tell you how to do that; here are two that I found using Google:

Basic SSH Setup On Ubuntu 10.04 Lucid Lynx Using OpenSSH Server
SSH—OpenSSH—Configuring

If you didn’t do this beforehand, you may still be able to do it if you can get to a command prompt.

Anyway, the actual fix is to (re-)install the latest NVIDIA driver for your system. They will be compiled against the new Linux kernel and then everything should work fine. To find the correct NVIDIA driver, go to the NVIDIA Driver Downloads page, and use the dropdowns to select the correct driver for your system.  Download it to your local system, then upload it to your Linux PC (if you have SSH access working then you can use an SFTP client, such as WinSCP or Transmit, to upload your driver file).  Once you have it on your PC, from a command prompt navigate to the directory where you put the driver and then change the permissions to make it executable:

sudo chmod +x driver_upgrade_script_filename

Now try running the script (it should have a .run extension):

sudo ./driver_upgrade_script_filename

It should not complain that the Gnome Display Manager or KDE Display Manager is running (if it were, you wouldn’t be in a state of near-panic right now), but if you were just doing a regular update you’d have to do this when the GDM/KDM is stopped. For a guide that covers that scenario, see How To Install Official Nvidia Drivers in Linux, or just know that to stop the display manager,

sudo /etc/init.d/gdm stop

should stop the Gnome Display Manager, or if you’re using KDE then the command would be

sudo /etc/init.d/kdm stop

Most sources I’ve seen suggest that you answer yes to any questions the installer may ask. The only one I’d be cautious about is letting it create a new xorg.conf if you are using a customized one (which you may well be if you’ve used any of my previous HTPC-related articles). If you have edited xorg.conf, then I’d make sure you at least have a backup before letting the installer create a new one, so you can revert back to your custom one (or compare the two and insert your customizations into the new one) if necessary.

Under Ubuntu, you may get a message similar to “Provided install script failed”. That will happen every time you update the NVIDIA driver this way and it is normal. Just ignore it and continue the installation. If you get “Error locating kernel source”, run  sudo apt-get install kernel-source  from the command prompt, then run the driver upgrade script again.

When the installer has successfully finished, reboot the system and when it comes back up, hopefully you should be happy again!

How to send an e-mail notification when someone dials a particular number in FreePBX

 

Important
This is an edited version of a post that originally appeared on a blog called The Michigan Telephone Blog, which was written by a friend before he decided to stop blogging. It is reposted with his permission. Comments dated before the year 2013 were originally posted to his blog.

Someone in the PBX in a Flash forum wanted to know if there was some technique that could be used to get an e-mail alert if a user on the system dialed 911.  There are probably many ways this could be done, but here was the way I thought would work.  This has not been tested in a working installation so please note the disclaimer at the end of the article.  I DO NOT guarantee that this will work on your FreePBX installation!

EDIT (November 24, 2012): Another approach to doing this would be to add some custom dialplan to the [macro-dialout-trunk-predial-hook] context in extensions_custom.conf.  See How to use the FreePBX [macro-dialout-trunk-predial-hook] macro and regular expressions to blacklist or whitelist outgoing calls on all trunks for more information on this technique, which would allow you to easily detect outgoing calls to a particular number on just about any trunk with only a few lines of code, eliminating the need to create a CUSTOM trunk as shown below.  Either method will work, so do whichever you’re more comfortable with.

1. First, add a small additional context to /etc/asterisk/extensions_custom.conf (note that you will probably need to copy and paste this into a text editor to get the first line of the context complete and without line breaks where they shouldn’t be):

[custom-notify-email] exten => _X!,1,TrySystem(echo "This is to notify you that ${CALLERID(name)} at ${CALLERID(num)} has called 911" | mail -s "911 call notification" you@youraddress.com)
exten => _X!,n,Goto(from-internal,0000${EXTEN},1)
exten => h,1,Macro(hangupcall,)

Note that the first line of the context (not counting the context label line) contains the actual email to be sent.  Replace the various elements of the e-mail (body, subject, destination address) with appropriate elements for your situation. In the second line of the context, note that I’m prepending a four-digit code of  “0000” to the number dialed before sending it back into the dial plan.  This code can be anything you want and any number of digits you want, but it should start with something that a user would never dial when making a regular call.  Therefore, things like “0000”, “111111”, or even “*****” could be good choices, while “9876” would be a poor choice because a user might actually attempt to call a number such as “987-6911”.  One PBX in a Flash forum user reported that “0000” conflicted with Astridex in some way, so that’s why I’m taking pains to explain this.  Since the user isn’t expected to dial these digits, you could even use something like “010100001111”, just as long as it’s a code used uniquely for this purpose.

2. Create a CUSTOM trunk. Make the trunk name whatever you like, but for the Custom Dial String use:

Local/$OUTNUM$@custom-notify-email

When you set it up it should look like this:

CUSTOM trunk (here named Send-email-notification) sends calls to custom-notify-email context

3. Assuming you’re using this to monitor 911 calls, create a NEW emergency 911 Outbound Route that duplicates your existing 911 route (In FreePBX 2.9 or later you can click on the “Duplicate Route” button). In the duplicate (which should be right underneath the original in priority) change the dial pattern from 911 to 0000|911 (but if you used something other than 0000 in step 1, use the same thing here).  What this does is strip off the digits that were prepended to the number by the custom-notify-email context — this is done so you don’t create an endless loop. Note the pattern I have shown assumes you are using FreePBX 2.7 or earlier OR are using the Swiss Army Knife module to restore the pre-2.8 dial pattern text box in your Outbound Routes — if you haven’t done that then be sure you get each component of the dial pattern in the correct little box.

DUPLICATE of original 911 emergency route that strips prepend in dial pattern (route has been renamed to 911-strip-prepend). Note how Swiss Army Knife module restores textbox entry for dial patterns!

4. In your ORIGINAL emergency 911 Outbound Route, change the trunk selection to use only the CUSTOM trunk you created in step 2.

ORIGINAL 911 emergency route, with trunk selection changed to use CUSTOM trunk

That’s it. The call flow is as follows:

Someone dials 911, it goes to the original 911 outbound route, then to the custom trunk and from there to your custom context which sends the email, prepends 0000 (or the digits you have used instead) onto the number (for example, making it 0000911 internally), and sends it back to the from-internal dial plan. It hits the duplicate 911 outbound route which strips the prepended digits and sends the call to your original trunk selection for 911 calls.

I would STRONGLY urge you to make a test call and see if it all works as you expect, if your local 911 service allows you to do that (call them on the non-emergency number first to make sure it’s okay). See the disclaimer below!!

You could use this same technique for non-emergency calls, but you’d have to have an Outbound Route dedicated to just those calls (in other words, it should only contain dial patterns for the calls you are trying to monitor, and it needs to be higher in priority than any other Outbound Route that might ordinarily handle such calls.  Once you have that working you can apply the above technique, which among other things means you’ll be making a duplicate of that Outbound Route, and making adjustments to the original and the copy as described above.

Disclaimer: The above is just a suggestion of what SHOULD work, and should be considered UNTESTED. Do NOT rely on it until you have tested it yourself to make sure it works as you expect. I don’t guarantee it will do anything except take up more space on your hard drive, so it is solely up to YOU to make sure it works as you want.

How I upgrade Asterisk 1.8

 

Important
This is an edited version of a post that originally appeared on a blog called The Michigan Telephone Blog, which was written by a friend before he decided to stop blogging. It is reposted with his permission. Comments dated before the year 2013 were originally posted to his blog.

Note: This article was originally posted in August, 2011 and is very out-of-date.

This is just one of those things that I figured it might not hurt to put into a blog post so I can find it later if I ever need to.  This is the procedure I use to upgrade Asterisk 1.8 when a new release appears that has a fix that I feel I need, or that closes a security hole.  PBX in a Flash users should NOT do this, and FreePBX Distro users probably shouldn’t do this either, as you have your own respective upgrade mechanisms.  This is for folks who have either built a system from scratch, or who (like me) started out with a distro but the decided to go your own way as far as upgrades are concerned.  Note that I am only saying that this is how I do it.  I am NOT telling you to do it this way, and if you do so you do it at your own risk.

There are the steps from the CentOS Linux command prompt.  Some of them need further explanation and those have a footnote number next to them.  Do NOT enter the footnote number from the command prompt! Also, in these examples I’m using Asterisk 1.8.5.0 (the current release version as I write this) as the version I’m installing, but you should go to http://downloads.asterisk.org/pub/telephony/asterisk/releases/ and find the current version and use that instead.  If the lines overflow the width of the column, you should probably copy and paste the entire block into a text editor so that you can see the complete lines and know where the line breaks are supposed to be.

cd /usr/src
wget http://downloads.asterisk.org/pub/telephony/asterisk/releases/asterisk-1.8.5.0.tar.gz ¹
tar xvfz asterisk-1.8.5.0.tar.gz ¹
cd /usr/src/asterisk-1.8.5.0 ¹
make clean
contrib/scripts/get_mp3_source.sh
./configure
make menuselect ²
/root/stopnoise ³
make
make install

After doing this I find it’s easiest to just reboot the system to nip any “weirdness” in the bud. Some Linux purists will hate that idea (it seems to be a badge of pride among some of them to see how many days they can run a system without rebooting), and if you don’t want to reboot, feel free not to — it’s your system. Many people will stop Asterisk before starting the upgrade procedure by doing amportal stop at the beginning, and amportal start at the end, but since I usually reboot anyway I’ve never found the need to do that (the upgrade seems to go just fine even if Asterisk is running at the time, so I’m not sure why so many people think they have to stop Asterisk first — probably a case of one person did it, so everyone else follows like lemmings to the sea). However, if you don’t plan on rebooting, then you must stop and restart Asterisk to get it to use the upgraded version.  If I want to only restart Asterisk for some reason, I usually go into the Asterisk CLI and do “core restart when convenient” so that the system will restart as soon as there are no calls in progress.

I do NOT use the flite synthesized voices (I can’t stand them; they are far too mechanical for my taste) so you won’t find any instructions here pertaining to those.

Now the footnotes:

¹ Use the correct version number for the version of Asterisk you are installing in place of 1.8.5.0

² When you run “make menuselect” it will bring up a menu that lets you select various options. You will want to pay attention to what is selected and what is not. Typically I need to make these changes:

Under Add-ons, I select everything EXCEPT chan_ooh323 — most of the others are required for FreePBX to function properly. Under Applications, I use the defaults. Under Bridging Modules through PBX Modules, everything that is not X’ed out is selected. Under Resource Modules everything that is not X’ed out is selected except res_pktccops (NOTE: If res_srtp has XXX next to it and you would like to enable SRTP support, stop here and read the note at the bottom of this article). Under Test Modules NOTHING is selected. Under Compiler Flags, LOADABLE_MODULES is selected by default and in addition I select G711_NEW_ALGORITHM and G711_REDUCED_BRANCHING. Under Voicemail Build Options through Module Embedding I just accept the defaults. Under Core Sound Packages through Extras Sound Packages I accept the defaults and also add the sounds corresponding to the language and codecs I use on my system (in my case the *-EN-WAV and *-EN-ULAW packages, and if I had any wideband endpoints I’d also use the *-EN-G722 packages). So, the only screens on which I make changes (in other words, I don’t just accept the defaults) are the Add-ons, Compiler Flags, and the three sound-related screens. Note that the Compiler Flags are just a personal preference (I just think the new algorithm may make G.711 calls a bit clearer) and the sounds MAY not need to be reloaded on every upgrade, but I’d rather be safe and include them, just in case some of the sound files have been updated.

³ This is a bash script I have in my /root directory that contained the following three lines prior to Asterisk 1.8.12.0:

#!/bin/bash
sed -i 's/ast_verb(4, "ast_get_srv: SRV lookup for/ast_verb(11, "ast_get_srv: SRV lookup for/' main/srv.c
sed -i 's/ast_verb(4, "doing dnsmgr_lookup for/ast_verb(11, "doing dnsmgr_lookup for/' main/dnsmgr.c

Starting with Asterisk 1.8.12.0 it appears they changed the default value in the last line, so now I use this:

#!/bin/bash
sed -i 's/ast_verb(4, "ast_get_srv: SRV lookup for/ast_verb(11, "ast_get_srv: SRV lookup for/' main/srv.c
sed -i 's/ast_verb(6, "doing dnsmgr_lookup for/ast_verb(11, "doing dnsmgr_lookup for/' main/dnsmgr.c

If either or both of the phrases “doing dnsmgr_lookup for …” and/or “ast_get_srv: SRV lookup for …” are familiar (and annoying) to you, then you may want to use this script. Otherwise, you can just skip this instruction. For more information, see this thread in the PBX in a Flash forum.

NOTE REGARDING MISSING SRTP SUPPORT: It is possible to add this by following this procedure:

In your browser go to ftp://ftp.owlriver.com/pub/local/ORC/srtp/ (your browser must support the ftp protocol – try Firefox if yours doesn’t). You should see a file named srtp-1.4.4-1orc.src.rpm or perhaps a newer version. Download it and then move it to a directory (such as /tmp or /root) on your Asterisk server. Then do this, changing the version number if you got a different one:

cd (whatever directory you put the file into)
rpm -ivh srtp-1.44-1orc.src.rpm
cd /usr/src/redhat/SOURCES/srtp

(If the srtp directory does not exist then cd /usr/src/redhat/SOURCES/ and tar xvf srtp-1.4.4.tgz)
./configure
make
make install

Then go back and restart the upgrade procedure, starting at the second cd … command and make clean. When you get to make menuselect, res_srtp should now be enabled. Note that this is not the only thing you need to do to make SRTP functional; at a bare minimum you would beed to add the line encryption=yes to the extension’s configuration, and even that would not be sufficient for some devices due to a so far unpatched bug in Asterisk. But, that is beyond the scope of this article.

How to block a single extension’s ability to make outgoing toll calls in FreePBX

 

Important
This is an edited version of a post that originally appeared on a blog called The Michigan Telephone Blog, which was written by a friend before he decided to stop blogging. It is reposted with his permission.
Courtesy Phone

Image by zacklur via Flickr

EDIT (May, 2018): FreePBX and Asterisk users that wish to continue using Google Voice after Google drops XMPP support should go here: How to use Google Voice with FreePBX and Asterisk without using XMPP or buying new hardware.

This question comes up a lot and rather than having to re-type the answer each time I see it posted in some forum, I decided to put it here, where I can just link to it.  If you want to know why this works, read my previous article, Asterisk hiding a useful feature in plain sight by giving it a “cute” name.

Many organizations have a single extension that is a “house phone” for visitors, and they don’t want anyone to be able to use that phone to make “off-site” calls.  The thing you must decide is, do you want your users to only be able to make in-house calls, or do you want to in addition allow calls to local and toll-free numbers? It makes a bit of difference in how you do this.  And remember, in most places, by law you MUST allow calls to 911 or whatever your local emergency number might be — if you block emergency calls and someone tries to use that phone to summon an ambulance or get other necessary emergency help and is unsuccessful in doing so, then prepare to have your butt sued off (and possibly even serve some time in prison), and I don’t have a bit of sympathy for you.  I don’t care what reasons you may think you have for wanting to block emergency calls, just DON’T DO IT.

Anyway, here’s the basic technique:

1.  Create a Trunk: (EDIT: This step is unnecessary in the most recent versions of FreePBX). If you want to allow “free” off-premises calls, then the easiest thing to do is create an ENUM trunk, if you haven’t done so already.  If you DON’T want to allow free calls, then create a “dummy” trunk for the purpose.  Create a CUSTOM trunk (not SIP or IAX2, etc.), name it Blocked, and make the Custom Dial String Local/congestion@app-blackhole — that’s all you have to do. For extra safety, you can also check the “Disable Trunk” checkbox (this should play a recording saying that all circuits are busy, or something to that effect, whereas leaving the trunk enabled would play “fast busy” tones). Then submit the changes.

2.  Create an Outbound Route: Give the Outbound Route any name you like. In the “Dial Patterns that will use this Route” section, enter the patterns you do NOT want the extension to be able to dial (in the third field of a pattern if using FreePBX 2.8 or higher) followed by the extension number that you want to restrict (in the fourth field in FreePBX 2.8 or higher, or after a forward slash character if using a lower version).  I’m going to show the following examples in the syntax used in FreePBX 2.7 (EDIT: you would also use this syntax in FreePBX 12 or later, if under Settings | Advanced Settings, in the “GUI Behavior” section you have set Enable The Old Style FreePBX Dial Patterns Textarea to True).  Let’s say you want to block calls from extension 234:

To block all calls of 11 digits or more (in case you have “local” 10 digit dialing):
XXXXXXXXXXX!/234

To block all calls of 8 digits or more (allowing 7 digit local calls):
XXXXXXXX!/234

To block all calls of 4 digits or more (in case you have three-digit extensions and want to allow in-house and 911 calls only):
XXXX!/234

In the Outbound Route trunk selection, (EDIT: if you have a recent version of FreePBX, simply do not select any trunks at all in the “Trunk Sequence for Matched Routes” section of the Outbound Route, and then optionally select a failure announcement or whatever treatment you want to give the call in the “Optional Destination on Congestion” section. Otherwise, if you are still running an older version of FreePBX) select whichever trunk you created in Step 1 (ENUM or Blocked).  Select only that one trunk.  Note that if you “disabled” the Blocked trunk it may be grayed out, but you still should be able to select it as a trunk choice, and that should be sufficient to keep FreePBX from complaining that you haven’t made a trunk selection.

Priority is important! Make sure this Outbound Route appears in your list of Outbound Routes BELOW any routes that handle calls you want to allow (your emergency route(s) for sure, and possibly routes that handle Toll-Free calls if you want to allow those), but ABOVE any routes that would normally be used for the type of calls you want to restrict.  Remember that this route will only restrict calls that match the patterns, so if you only restrict calls that are 8 digits or more and you have a lower-priority route that handles 7-digit local calls, those calls should still go out.

Just a note about use of an ENUM trunk (EDIT: Optional and not necessary in newer versions of FreePBX).  If someone calls a number that is registered as an ENUM number, it will go out as a direct SIP call, bypassing your normal SIP or IAX providers, so it won’t cost you a dime.  The vast majority of numbers are NOT reachable via ENUM so if you use an ENUM trunk as your “blocker” trunk, it will be a very rare thing if a call actually connects that way, but if it does you won’t be paying for it.  Sometimes U.S. or Canada Toll-Free numbers are reachable via ENUM and sometimes they are not — it’s actually pretty much a crap shoot whether it will even work at all.  So if you want to specifically allow toll-free calls, don’t count on ENUM to handle them, but be aware that in some cases they might go through via ENUM, at no cost to you (other than whatever you may pay for your Internet connection, of course).

Be sure to make some test calls from the extension to make sure everything works as you expect.  And double-check to make sure you have not blocked emergency (911, or whatever your local number is) calls!

If you need to do blocking for more than one extension, you can either use patterns (rather than single extension numbers) after the forward slash, or simply add new blocking rules.  For example, you could do this:

Block all calls of 4 digits or more from extension 234 or 235:
XXXX!/23[45]

Block all calls of 4 digits or more from extension 230 through 239:
XXXX!/23X

Block all calls of 4 digits or more from extension 234, and block all calls to 1-900 numbers from extension 288:
XXXX!/234
1900XXXXXXX/288
900XXXXXXX/288

 

How to keep one group of extensions from being able to call another group of extensions in FreePBX

 

Important
This is an edited version of a post that originally appeared on a blog called The Michigan Telephone Blog, which was written by a friend before he decided to stop blogging. It is reposted with his permission. Comments dated before the year 2013 were originally posted to his blog.

FreePBX is NOT designed for multi-tenant use. Yet a lot of people will still try to, for example, run two small companies off the same FreePBX server. The question then invariably arises “How do I keep one company’s users from calling the other company’s extensions?”

Just yesterday in the FreePBX forum, someone asked:

Imagine I have extensions 100-110 and I name those CustomContext “GroupA” and I name 200-210 as “GroupB”. Can anyone tell me how I’d eliminate GroupA and GroupB from dialing each other?

And I replied as follows:

Create two new contexts in /etc/asterisk/extensions_custom.conf (just add these to the bottom of the file):

[from-group-a] exten => _2XX,1,Goto(app-blackhole,congestion,1)
exten => _[*0-9]!,1,Goto(from-internal,${EXTEN},1)
exten => h,1,Hangup()

[from-group-b] exten => _1XX,1,Goto(app-blackhole,congestion,1)
exten => _[*0-9]!,1,Goto(from-internal,${EXTEN},1)
exten => h,1,Hangup()

After you do that:

Go to the extension configuration page for each extension in Group A and change the context from from-internal to from-group-a.

Go to the extension configuration page for each extension in Group B and change the context from from-internal to from-group-b.

The way this works is if someone in Group A attempts to call an extension in the 200-299 range, OR if someone in Group B attempts to call an extension in the 100-199 range, the call is diverted to “congestion” (a fast busy signal). Otherwise, the call goes to the from-internal context and is processed in the normal way.

No nice way to do this from a GUI page, unfortunately. But, this is pretty simple, I think.

EDIT: There may be a slightly more elegant way to do this, that only involves adding ONE additional context to /etc/asterisk/extensions_custom.conf:

[from-restricted-exts] exten => _2XX/_1XX,1,Goto(app-blackhole,congestion,1)
exten => _1XX/_2XX,1,Goto(app-blackhole,congestion,1)
exten => _[*0-9]!,1,Goto(from-internal,${EXTEN},1)
exten => h,1,Hangup()

Then you would change the context for all “restricted” extensions from from-internal to from-restricted-exts — this should have the exact same effect as the above contexts (if you don’t understand why, see Asterisk hiding a useful feature in plain sight by giving it a “cute” name).

What I did not really go into in that reply is that this does NOT provide 100% separation.  Although it prevents a user in one group from calling a user on the other directly, it does not address a host of other issues that could arise.  Just as one example, there is nothing that would stop a user in “Group A” from transferring a call to a user in “Group B”.  Did I mention that FreePBX is NOT designed to be a multi-tenant system?

Probably the best solution for multi-tenant use is to run separate installations of Asterisk and FreePBX for each tenant.  You can run them on separate servers, or on separate Virtual Machines on the same server, but be careful if you do the latter, because some VM’s work better than others for the purpose.  The PBX in a Flash folks would tell you, for example, that they’ve never had a problem running PBX in a Flash under Proxmox, but always seem to have issues if trying to run it under VMware.  But others will say that with the right tweaks (and by installing VMware Tools) they’ve made it work under VMware.  But I think that if you only have one server available, running two installs of Asterisk and FreePBX in Virtual Machines is better than trying to make FreePBX (and perhaps Asterisk itself) do something it is clearly not designed to do.

Asterisk hiding a useful feature in plain sight by giving it a "cute" name

 

Important
This is an edited version of a post that originally appeared on a blog called The Michigan Telephone Blog, which was written by a friend before he decided to stop blogging. It is reposted with his permission. Comments dated before the year 2013 were originally posted to his blog.
easter eggs in the stage of painting

Easter Eggs (Image via Wikipedia)

Somewhere in FreePBX 2.7 or thereabouts, it became know that there was a feature of FreePBX Outbound Route dial patterns, were you could use a /CallerID extension. This (among other things) basically lets you limit the use of an Outbound Route to a particular extension or group of extensions.  It’s a very useful feature, but wasn’t widely announced or promoted at the time.  I finally figured out why.

Thing is, it’s NOT a FreePBX feature, it’s a feature of Asterisk.  Anywhere in an Asterisk dial plan where you have a line that starts with

exten => _somepattern,…

you can use the Caller ID modifier, like this:

exten => _somepattern/callerid,…

In which case the pattern won’t be matched unless the current Caller ID number (which on an internal call is the number of the calling extension) matches whatever you’ve replaced callerid with.  Callerid can itself be a number or a pattern.

The real kick in the head is that it appears this feature has been around for a LONG time.  It was definitely in Asterisk 1.4.  Yet virtually none of the documentation you see on Asterisk even mentions this feature.  It might as well have been an “Easter Egg” hidden in the software, for all anyone knew of it.  Well, I finally figured out why — the Asterisk folks hung a “cute” name on it, and it stuck.

They called it ex-girlfriend logic.  The idea is that you can use it to stop an ex-girlfriend from bothering a particular user on your system (at least in raw Asterisk, though I don’t think that’s directly supported in FreePBX).  Besides being a bit sexist, it’s also about the last terminology anyone would think to Google on if they were trying to find out about this feature.  So while people were writing third-party modules like Custom Contexts and Outbound Route Permissions in FreePBX, it now turns out that essentially the same basic functionality was there all along, but hardly anyone (at least in the FreePBX world) knew about it until around about the time of FreePBX 2.7 or so.  If you can find anything at all about this feature in “official” Asterisk documentation (that doesn’t include third-party sites!), you’re a better searcher than I.

Makes you wonder if there are any OTHER cool features in Asterisk that are hidden in plain sight, under unfortunate descriptive names that no one would ever think to use when searching for such a feature!

 

Problems you may encounter when attempting to install phpMyAdmin on your Centos server, and how to solve them

 

Important
This is an edited version of a post that originally appeared on a blog called The Michigan Telephone Blog, which was written by a friend before he decided to stop blogging. It is reposted with his permission. Comments dated before the year 2013 were originally posted to his blog.

This article was originally published in August, 2011 and may contain outdated information.

phpMyAdmin logo

Image via Wikipedia

I just spent an interesting couple of hours trying to install phpMyAdmin on an Asterisk server running CentOS 5.5. As I encountered each problem and solved it, I had to wade through a lot of pages that weren’t applicable to my installation, etc. Since many readers of this blog run similar configurations I thought I’d just list the hiccups I encountered, and what I had to do to solve them. Note that some distributions come with phpMyAdmin already installed, so make sure you don’t already have it before you try to install it!

NOTE: Think carefully about whether you really want to follow the instructions below, particularly if it requires adding a repository. If you do that, make sure you only install the software you actually need from that repository, then disable it (set enabled=0). If you don’t do that, you could easily get into a situation where some of your curent software (such as PHP) simply will not upgrade no matter what you do. And if you are running a PBX “install and go” distribution, they may specifically warn you not to add repositories, or it will break your installation, so don’t do it!

If you do anything suggested below, you do it at your own risk!

• yum install phpmyadmin doesn’t work — try using the dag repository — there are several pages on the Web that tell how to do this. Use Google to search for “how to enable the dag repository” (without the quotes) if you need help. The basic idea is you need to create a file called /etc/yum.repos.d/dag.repo (with the proper permissions, ownership, etc.) and put something like this inside:

[dag] name=Dag RPM Repository for Red Hat Enterprise Linux
baseurl=http://apt.sw.be/redhat/el$releasever/en/$basearch/dag
gpgcheck=1
enabled=1

BUT you also need to install a GPG key, and getting THAT can be a bit of a problem. Some instructions will tell you to do this:

rpm –import http://dag.wieers.com/rpm/packages/RPM-GPG-KEY.dag.txt

That link no longer works, and you have to do this instead:

rpm –import http://apt.sw.be/RPM-GPG-KEY.dag.txt

But for some people even THAT doesn’t work, in which case it’s suggested you use wget to obtain the file, then import it:

wget http://apt.sw.be/RPM-GPG-KEY.dag.txt
rpm –import RPM-GPG-KEY.dag.txt

I’m being a bit non-specific because the instructions could change, and I’d prefer you find a current reference on how to enable this repository. Also, some may prefer to install RPMforge, which is a collaboration of Dag and other packagers. Regardless of the effort involved, I do suggest you install phpMyAdmin using yum, because it will install everything in the correct locations for CentOS, and you don’t have to compile it or anything like that.

Note that when you do install phpMyAdmin using yum, it may also install required dependencies such as libmcrypt and php-mcrypt (another advantage to using yum).

• You don’t have permission to access /phpmyadmin/ on this server.

Go to /etc/httpd/conf.d/phpmyadmin.conf
Under the line:
Allow from 127.0.0.1
You could add a line to allow access from your local network, for example:
Allow from 192.168.0.0/255.255.255.0
(But use values appropriate to your network).

If you are accessing the box remotely, then add a line allowing access from your IP address. Be VERY careful, because you don’t want to let the entire world into your databases!

• Existing configuration file (./config.inc.php) is not readable.

If you’re doing this on a system running FreePBX, scroll down to where I discuss changing the ownership of all phpMyAdmin-related files and directories to be the same as the MySQL user. Otherwise, the easiest solution (though not necessarily the most secure) is to change the permissions of the file /usr/share/phpmyadmin/config.inc.php from the default of 640 to 644 (add user read permission). If no one can get to your system from outside your local network, this probably isn’t an issue, but if anyone has a better idea on this, feel free to leave a comment.

• “Error
The configuration file now needs a secret passphrase (blowfish_secret).”

Open /usr/share/phpmyadmin/config.inc.php and find this section:

* This is needed for cookie based authentication to encrypt password in
* cookie
*/
$cfg[‘blowfish_secret’] = ‘oh my this is such a wonderful passphrase‘; /* YOU MUST FILL IN THIS FOR COOKIE AUTH! */

Insert any phrase you like (within reason) between the second pair of single quotes in the last line shown above (but don’t use ‘oh my this is such a wonderful passphrase‘, I just inserted that as an example.  Be creative!).  Don’t worry, this isn’t something you’ll actually have to type in every time you want to use phpMyAdmin.

• #1045 – Access denied for user ‘root’@’localhost’ (using password: YES)

You don’t login as root, you use your MySQL username and password. In FreePBX-based systems these can be found in /etc/amportal.conf, in the AMPDBUSER and AMPDBPASS settings. BUT… if you enter a wrong user name before logging in correctly, it may have already set a cookie with that username and password and then you won’t be able to get in even if you DO use the correct username and password. The solution is to clear all browser cookies for the address of your server, then try again — and make sure you get it right this time! 😉

I will note here that you can avoid some of these cookie-related issues, probably including those mentioned above, by going into /usr/share/phpmyadmin/config.inc.php and finding this section:

/* Authentication type */
$cfg[‘Servers’][$i][‘auth_type’] = ‘cookie’;

If your system is behind a hardware firewall or is otherwise VERY secure, you could change the auth_type from ‘cookie’ to something else, such as ‘http’. This will save you a lot of frustration during the login process, but at the possible expense of making your database less secure.  For those concerned about security, a document on the phpMyAdmin wiki advises you to “See the page on Security or the multi–user sub–section of the FAQ for additional information, especially FAQ 4.4.”  I personally found their security documentation rather useless, because they make a lot of suggestions but provide no specific examples of how to implement those suggestions.  Anyway, I personally feel that as long as a system is behind a good firewall that doesn’t permit anyone on the “outside” to access phpMyAdmin, ‘http’ is a good compromise between a security model that might drive you crazy (‘cookie’) and one of the other models that’s fairly insecure, such as ‘config’ (which some consider insecure because it stores your server username and password in plain text).  However, if your system is otherwise VERY secure and you just don’t want to have to enter a password to use phpMyAdmin, then it is possible to change the ‘auth_type’ to ‘config’ and (in the same config file), look for these lines:

/*
 * End of servers configuration
 */

And just above those lines, insert these lines:

$cfg[‘Servers’][$i][‘user’] = ‘mysqluser’;
$cfg[‘Servers’][$i][‘password’] = ‘mysqlpassword’;

Change mysqluser and mysqlpassword to the correct vales for your system (on a FreePBX-based system, these are the values in /etc/amportal.conf mentioned above).  I do not recommend using ‘config’ because it is less secure (be sure to read the page on Security mentioned above), but it’s up to you to decide how secure you want your system to be.

(I’m fully aware that any objections to storing the user and password values in plain text in the phpMyAdmin config.inc.php fall a bit flat when you realize the same values are stored in plain text in amportal.conf, but I also feel as though the fewer places those values are exposed, the better.  Why give potential attackers one more place to find this information?)

• phpMyAdmin – Error
Cannot start session without errors, please check errors given in your PHP and/or webserver log file and configure your PHP installation properly.

Check your /var/log/httpd/error_log – in my case, the first error message of each set contained a phrase like “open(/var/lib/php/session/sess_somerandomstring, O_RDWR) failed: Permission denied (13)” and I figured that the problem was another permissions issue.

On some sites I have found a suggestion that you change the ownership of all phpMyAdmin-related files and directories to be the same as the MySQL user (in the case of an Asterisk/FreePBX system, that would be asterisk:asterisk). On a FreePBX-based system, you could try this (check to make sure these are the correct paths before doing this):

chown asterisk:asterisk /usr/share/phpmyadmin -R
chown asterisk:asterisk /var/lib/php/session -R

If that doesn’t resolve the issue (or you’re doing this on a system that’s not running FreePBX), perhaps the easiest solution (though not necessarily the most secure) is to change the permissions of the offending file. If you have the same issue I had, try changing the permissions of the directory /var/lib/php/session from the default of 770 to 777 (add full user permissions).

Strangely, this one didn’t show up until after I’d successfully run phpMyAdmin a few times. Go figure. Also, after fixing this, I had to delete cookies again (as mentioned in the previous item) before I could log in, but that was when I still had the ‘auth_type’ set to ‘cookie’ (another reason I decided to change that to ‘http’).

Found and solved any other “gotchas” while installing phpMyAdmin under CentOS? Think I could have solved a problem in a better way? Feel free to share your solutions in the comments.

EDIT: There is one other thing that can happen after you install or update PHP on your system (as might happen if you let a FreePBX-based distribution do an upgrade).  You may start seeing PHP warning messages such as:

PHP Warning:  PHP Startup: mcrypt: Unable to initialize module
Module compiled with module API=20050922, debug=0, thread-safety=0
PHP    compiled with module API=20060613, debug=0, thread-safety=0
These options need to match
 in Unknown on line 0

If that happens try updating the dependencies that came with phpMyAdmin, for example:

yum update libmcrypt
yum update php-mcrypt

It was the second of those two that vanquished the PHP warning messages for me.

And why did I NEED to install phpMyAdmin, you ask?  Well, because someone (ahem) made a slight configuration error and caused an endless loop, that within the space of about ten seconds or so, generated over a THOUSAND bogus records in the ‘asteriskcdr’ (Call Detail) database.  The only easy way to I knew of at the time to clean them out was phpMyAdmin (since I don’t “speak” MySQL), but I don’t recommend you attempt something like that unless you know what you’re doing, because one wrong move and you could delete your entire FreePBX database (trust me, that would be a VERY bad thing!). In retrospect I probably could have used Webmin, since it also has the ability to access the MySQL database, but I didn’t think of that at the time.

Link: FreePBX security advisory – SIP extension types

 

Important
This is an edited version of a post that originally appeared on a blog called The Michigan Telephone Blog, which was written by a friend before he decided to stop blogging. It is reposted with his permission. Comments dated before the year 2013 were originally posted to his blog.
We can set defaults for all these, so why not extension type?

We can set defaults for all these, so why not extension type?

The SysAdminMan blog has posted a new article related to FreePBX security, that I strongly urge you to read if you are running FreePBX or any FreePBX-based distribution:

FreePBX security advisory – SIP extension types

The basic issue is that by default, FreePBX sets extensions to type=friend rather than the more secure type=peer.  The article says it’s for historical reasons but I suspect there have been other reasons at play here (pure stubbornness, perhaps?).  But with the growing body of evidence that type=friend is bad, and because FreePBX now has an Advanced Settings module that allows you to to change certain defaults (though not yet this one), I have put in a Feature Request asking that system administrators be allowed to select a default type for extensions.  We’ll see if it goes anywhere (and it might help if anyone who supports this idea would add a comment to that ticket), but given that in the past they’ve been reluctant to even entertain the idea of changing the default, I fear that they may once again refuse to even consider it.  And for those of us who want to keep our systems as secure as reasonably possible, that would be a real shame.

How to isolate a second router from the rest of your local network

 

Important
This is an edited version of a post that originally appeared on a blog called The Michigan Telephone Blog, which was written by a friend before he decided to stop blogging. It is reposted with his permission. Comments dated before the year 2013 were originally posted to his blog.

I was recently asked how to solve a particular problem and I came up with what I think is an interesting solution, especially given my overall rather limited knowledge of networking.  The issue was this: In the home in question, they have cable broadband and a router that feeds jacks throughout the house.  For security reasons, the homeowner never installed any kind of wireless networking (even though his primary router supports it, he keeps it turned off).  Also his primary router is down in the basement.

Recently he got his wife a Motorola XOOM table computer and wouldn’t you know, it requires Wi-Fi access to connect to the Internet.  In order to extend the range, and so that he or his wife could easily turn off the Wi-Fi when the XOOM isn’t in use, he bought a second Wi-Fi router and put it upstairs.  Note that this router is connected BEHIND the original router in the basement.  In other words, the sequence of connection is as follows:

Cable Modem —> Basement (Primary) Router —> Upstairs (Wi-Fi) Router —> Tablet Computer

Now, as I said, he is very security conscious.  So the question he asked me is, if someone managed to break into his Wi-Fi, is there a way to set it up so that they could ONLY get to the Internet, and not to any other system on his local network.  I said I didn’t know, but to first try accessing other machines on his network (the ones that had web interfaces, anyway) from the XOOM.  Turned out that he could do so without any problem.  Because the Wi-Fi router used a different network segment from the original (addresses in the 192.168.2.x range, whereas the original router handed out address in the 192.168.0.x range), as far as anything connected to the Wi-Fi router was concerned, anything on the primary router might as well have been on the Internet (please forgive the non-technical explanation, I’m probably missing several technical details here, but that’s the gist of the problem).

I didn’t think it would be a good idea to try to make the Wi-Fi router use the same address space for both WAN and LAN, and while I could assign it a static IP address on the WAN side, it had to be able to reach the router/gateway at 192.168.0.1.  So here is what we did.

On the PRIMARY router, we took a look at the LAN settings and found that its DHCP server was assigning addresses starting at 192.168.0.2.  We changed that to start at 192.168.0.5 (probably could have used 192.168.0.4 in retrospect).

This way, we could change the WAN address of the Wi-Fi router to use a STATIC IP address of 192.168.0.2, and (this is the important part) a NETMASK of 255.255.255.252.

This means that as far as the Wi-Fi router is concerned, there are only four valid IP addresses in the 192.168.0.x range:

192.168.0.0 (not used)
192.168.0.1 (primary router/gateway)
192.168.0.2 (Wi-Fi router)
192.168.0.3 (Reserved for “broadcast” as far as Wi-Fi router is concerned)

One thing to remember is that after changing the DHCP assignment on the PRIMARY router is that computers already using IP address 192.168.0.2 and 192.168.0.3 will not automatically vacate those addresses until their DHCP lease comes up for renewal.  So if you change the second router’s WAN address to 192.168.0.2, it may not actually be able to connect until the computer or device currently on 192.168.0.2 “loses its lease”.  Rebooting the primary router may help, but in some cases you may have to track down the computer with the conflicting address and shut it off, or if you know how, renew its IP address assignment (this can usually be done from within the network settings panel).  Eventually, though, it should work, and at that point you should find that devices connected to the secondary router cannot connect to any addresses in the 192.168.0.x range outside the three mentioned above, which means they won’t be able to “see” anything else on your network that’s been assigned a DHCP address.

This tip falls into the category of “it worked in this particular situation, but I don’t guarantee it will work for you”.  So if you try this, be sure to test to make sure that the other machines on your primary network are actually unreachable from the secondary router.

Now let the comments begin, telling me how there’s a better way to do this, or why it won’t work, or something to that effect…

A Perl script to rewrite the "static" IP address in the FreePBX Asterisk SIP Settings when it is changed by your ISP

 

Important
This is a heavily edited version of a post that originally appeared on a blog called The Michigan Telephone Blog, which was written by a friend before he decided to stop blogging. It is reposted with his permission. Comments dated before the year 2013 were originally posted to his blog.

This was originally posted in August, 2011. Unless you are deeply in love with Perl, I suggest you also take a look at the newer article, A Bash script to rewrite the "static" IP address in the FreePBX Asterisk SIP Settings when it is changed by your ISP. Although it is still considered experimental, it is simpler than the script shown here, does not require the installation of additional modules, and the text has been updated somewhat to reflect the changes in FreePBX since this article was written.

This post is going to be a bit long because I first need to explain the “why” behind this script, then how to obtain the prerequisite Perl modules, then the script itself and how to test it after installation.

If you are using a recent version of Asterisk and FreePBX you may be using the Asterisk SIP Settings module (under the “Tools” tab) to automatically set various SIP parameters.  This module is a great help to those who don’t know what they are doing, but there is a trap for the unwary (and in this case it’s NOT the fault of FreePBX – it’s a longstanding bug in Asterisk that’s the problem).

At the top of the Asterisk SIP Settings configuration page, in the NAT Settings section, there are two options that can be set.  The first is NAT and there are four possible choices:

  • yes = Always ignore info and assume NAT
  • no = Use NAT mode only according to RFC3581
  • never = Never attempt NAT mode or RFC3581
  • route = Assume NAT, don’t send rport

In theory, if you have a fixed IP address AND your Asterisk server is not behind an external router that does NAT translation, you should use “no” (and most of the rest of this article will not be relevant to you).  This article is intended more for home and SOHO users that both have their Asterisk server behind a hardware router of some kind, and that get their broadband service from a company that occasionally changes their IP address without warning.  For such users, the preferred setting is “yes”.  I’m not enough of a networking guru to tell you under what circumstances one of the other settings might be appropriate (if you understand this stuff, feel free to leave a comment and enlighten us).

FreePBX: Asterisk SIP Settings page, NAT Settings (Public IP Option)

It’s the next set of settings that can get us into trouble.  This is the IP Configuration and there are three possible choices:

  • Public IP
  • Static IP
  • Dynamic IP

If your IP address never changes AND you aren’t behind a hardware firewall then you can usually just set this to “Public IP” and let it go at that.  You will not be asked to fill in any other values.  But most users that are not in that situation will pick one of the other two choices, and this is where the problem arises.  Conventional wisdom has it that if your ISP ever changes your IP address without advance warning (which is the case for most cable broadband and DSL users), you should use the Dynamic IP setting.  In this case there is an auto-configure button that will fill out the fields for you, although you may need to fill in the Dynamic Host field yourself.  This is the “External FQDN as seen on the WAN side of the router and updated dynamically, e.g. mydomain.dyndns.com” (as explained if you mouse over the words “Dynamic Host”).  You can use a DynDNS address (or an address from a similar service) or an address you have purchased.  But the problem is that for some users, THIS METHOD SIMPLY DOES NOT WORK.

FreePBX: Asterisk SIP Settings page, NAT Settings (Dynamic IP Option)

If you try to use Dynamic IP and it won’t work for you, what happens is you will get all sorts of weird errors.  You may get one way audio, some calls may disconnect for no apparent reason after about five seconds, and you will see other weird errors in your CLI.  If you change this setting to “Static IP” and click the auto-configure button and then submit the changes, the problems magically go away – UNTIL your ISP changes your IP address, at which point you suddenly have no connectivity to the outside world.  If you ask for help, everybody and their brother will tell you to use the Dynamic IP setting, and the minute you try that you’ll get all the weird errors again.

FreePBX: Asterisk SIP Settings page, NAT Settings (Static IP Option)

So if that’s your situation, you need this Perl script.  Coupled with a cron job, it goes out and checks your IP address every five minutes and if it notices it has changed, it changes it in the MySQL database (same as if you entered it into the External IP text box on the Asterisk SIP Settings configuration page) and then reloads Asterisk.  Therefore, you can use the Static IP method and it hopefully it will work reliably.  If and when your IP address changes, you should only be down for about five to ten minutes at most (hopefully your broadband provider usually does such changes in the middle of the night!).

Prerequisites:

You still have to use a Dynamic DNS service to keep track of your IP address if you want external extensions to be able to find your server on the Internet.  It’s not required for this script to work, though, so I won’t say any more about that except to note that if you use a recent vintage hardware router, it probably has DDNS support built in.

You may have to install some Perl modules on your system.  This script uses two or three: WWW::Mechanize (only if you use the first variation of the script shown below), Data::Validate::IP, and DBD::mysql.  There are typically two ways to install any missing Perl modules on your system.  One is to do this from the Linux command prompt:

perl -MCPAN -e shell

This will put you into a Perl CPAN shell and if it’s the very first time you’ve ever run this, it may ask you to do some configuration first.  Go ahead and do it.  If you don’t know how to answer a particular question, accepting the default is usually a pretty safe bet (if you disagree with me on this, then you know enough to know how to answer the questions, so you don’t need my help). However there are a couple questions related to buffers where you have the option to not create one, and I usually don’t because I don’t spend much time in the Perl shell.  Just read the questions and either use the default answer, or another suggested answer that fits your preferences.  When it comes time to pick servers (from which you will download modules), just pick two or three that are close to you.

After you’ve done the configuration, just install each module (if you already have it, it may say “nothing to do” and stop).  Alternately, if you configured Perl to ask before downloading dependencies, you may need to answer “yes” a few times to allow dependencies to be downloaded and installed. To install the required modules from within the CPAN shell, just do these, one at a time:

install WWW::Mechanize (only if you use the first variation of the script)
install Data::Validate::IP
install DBD::mysql   (you might already have this).

To quit the CPAN shell, just type quit and press Enter.

Alternately, in some distributions you can get certain Perl modules from the distribution’s repository.  For example, in Centos you may be able to use:

yum install perl-WWW-Mechanize.noarch (only if you use the first variation of the script)
yum install perl-Data-Validate-IP.noarch
yum install perl-DBD-MySQL.noarch

Or in any Debian-based Linux, including Ubuntu Server, try these:

sudo apt install libwww-mechanize-perl (only if you use the first variation of the script)
sudo apt install libdata-validate-ip-perl
sudo apt install libdbd-mysql-perl

It’s likely you already have the Mysql module. Depending on your distro you may have to leave off the .noarch, or find a specific version in an appropriate repository.  Installing from the CPAN shell make take a bit more time for the initial configuration, and some people find the CPAN shell difficult to use, but you will always get the correct version of the module.

Note that if you use Webmin, there is a third way – you can install modules from the Other | Perl Modules | Install Module page.  BUT, that may not work correctly until you have configured CPAN as mentioned above.  Don’t let that stop you from trying it, though!

The Script:

There are now two versions of this script. One uses WWW::Mechanize to get your IP address from a web site that returns only your IP address, while the second uses a dig command to get your IP address. We recommend the second one, since public sites that return only your IP address have a nasty habit of disappearing. Note that as always, these WILL overflow the lines in WordPress, so you will want to cut and paste your preferred script into a text editor.  Also note that WordPress MAY change apostrophes and quotes into “prettified” versions, and if it does that will totally mess up Perl.  I’m going to put this in a preformatted text block so hopefully WordPress won’t change anything (it doesn’t appear that it has), but you never know.  One final note, don’t confuse backticks (`) with apostrophes (‘) – backticks are used to run a command that would normally be run from a Linux command prompt.

These scripts were written for use with FreePBX 2.11; there are a couple of lines that need to be changed for FreePBX 12 and above which will be posted below the main scripts:

#!/usr/bin/perl

# This program gets the current IP address (as assigned by the ISP) from
# a web page and modifies the FreePBX Asterisk SIP settings if the
# external IP address has changed. Invoke it as cron job that runs every 5 minutes.

use strict;
use warnings;
use WWW::Mechanize;
use Data::Validate::IP qw(is_public_ipv4);

# GET CURRENT IP ADDRESS
my $mech = WWW::Mechanize->new( autocheck => 1 );

# NOTE THE http QUERY IN THE NEXT LINE - PLEASE PASTE THIS INTO YOUR WEB
# BROWSER AND MAKE SURE IT RETURNS YOUR IP ADDRESS AND NOTHING ELSE.
$mech->get('http://some_web_site_that_returns_your_IP_address');
$mech->success or die 'Cannot connect to web site';
my ($ip) = ($mech->content() =~ /(d+.d+.d+.d+)/);

# VALIDATE RESULT RECEIVED

if (is_public_ipv4($ip)) {

	# SET UP TO CONNECT TO MySQL DATABASE
	use DBI();

	# CONNECT TO DATABASE
	my $connect = DBI->connect("DBI:mysql:database=asterisk;host=localhost", "user", "pw", {'RaiseError' => 1});

	# GET IP ADDRESS FROM DATABASE
	my ($externip) = $connect->selectrow_array("SELECT data FROM sipsettings WHERE keyword like ?", undef, "externip_val");

	# COMPARE IP ADDRESSES

	if ($externip ne $ip) {

		# WAIT 5 SECONDS AND RECHECK IP TO AVOID FALSE POSITIVES

		sleep 5;
		$mech->get('http://some_web_site_that_returns_your_IP_address');
		$mech->success or die 'Cannot connect to web site';
		my ($ip) = ($mech->content() =~ /(d+.d+.d+.d+)/);
		if ($externip ne $ip) {

			# IP HAS CHANGED SO UPDATE IP ADDRESS IN DATABASE
			$connect->do("UPDATE sipsettings SET data = ? WHERE keyword = ?", undef, "$ip", "externip_val");

			# WRITE CONFIG FILES AND RELOAD ASTERISK
			`/var/lib/asterisk/bin/module_admin reload`;

			# OPTIONAL SEND EMAIL TO SYSTEM ADMINISTRATOR(S)

			# my $mailstring = 'echo "This is an automated message - please do not reply. Either we had a power or Internet outage (in which case there is a slight chance you may receive this message even if our IP address is unchanged), or our Internet Service Provider has changed the IP address of our phone server to ' . $ip . '" | mail -s "ISP may have changed our IP address" someaddress@gmail.com,anotheraddress@somewhere.com';
			# system($mailstring);
		};
	};
};

Variation #2 (recommended) – note, do NOT confuse backticks and apostrophes, since both are used in this script and they are NOT interchangeable!

#!/usr/bin/perl

# This program gets the current IP address (as assigned by the ISP) from
# OpenDNS and modifies the FreePBX Asterisk SIP settings if the external IP
# address has changed. Invoke it as cron job that runs every 5 minutes.

use strict;
use warnings;
use Data::Validate::IP qw(is_public_ipv4);

my $dig = 'dig +short myip.opendns.com @resolver1.opendns.com';
my $ip=`$dig`;
chomp $ip;
if ($ip=~/((\d){1,3}\.){3}(\d){1,3}/) {
	if (is_public_ipv4($ip)) {

		# SET UP TO CONNECT TO MySQL DATABASE
		use DBI();

		# CONNECT TO DATABASE
		my $connect = DBI->connect("DBI:mysql:database=asterisk;host=localhost", "user", "pw", {'RaiseError' => 1});

		# GET IP ADDRESS FROM DATABASE
		my ($externip) = $connect->selectrow_array("SELECT data FROM sipsettings WHERE keyword like ?", undef, "externip_val");

		# COMPARE IP ADDRESSES

		if ($externip ne $ip) {

			# WAIT 5 SECONDS AND RECHECK IP TO AVOID FALSE POSITIVES

			sleep 5;
			$ip=`$dig`;
			chomp $ip;
			if ($ip=~/((\d){1,3}\.){3}(\d){1,3}/) {
				if (is_public_ipv4($ip)) {
					if ($externip ne $ip) {

						# IP HAS CHANGED SO UPDATE IP ADDRESS IN DATABASE
						$connect->do("UPDATE sipsettings SET data = ? WHERE keyword = ?", undef, "$ip", "externip_val");

						# WRITE CONFIG FILES AND RELOAD ASTERISK
						`/var/lib/asterisk/bin/module_admin reload`;

						# OPTIONAL SEND EMAIL TO SYSTEM ADMINISTRATOR(S)

						# my $mailstring = 'echo "This is an automated message - please do not reply. Either we had a power or Internet outage (in which case there is a slight chance you may receive this message even if our IP address is unchanged), or our Internet Service Provider has changed the IP address of our phone server to ' . $ip . '" | mail -s "ISP may have changed our IP address" someaddress@gmail.com,anotheraddress@somewhere.com';
						# system($mailstring);

					};
				};
			};
		};
	};
};

NOTES on the above scripts, including THINGS YOU MUST CHANGE:

In the first script, change both occurrences of http://some_web_site_that_returns_your_IP_address to a web address that returns only your IP address and nothing else. Enter the link into a web browser to make sure you get the expected result — it should show your external IP address and nothing else. These services tend to come and go, and you’ll need to find one that returns your IP address, and ONLY your IP address, with no extraneous HTML formatting or text. If you don’t know of such a source, then try the second variation.

These rest of this applies to both scripts:

Note the two bolded variables user and pw. These must be changed to the correct values for YOUR system. You will usually find these in one of two places. You can look in /etc/amportal.conf and look for the variables AMPDBUSER and AMPDBPASS — these will usually be near the bottom of the file in newer installs, in a “— CATEGORY: Bootstrapped or Legacy Settings —” section, but they can be anywhere in the file.

Another place they may be found is in the file /etc/freepbx.conf — in that file, look for lines similar to:

$amp_conf[‘AMPDBUSER’] = ‘freepbxuser’;
$amp_conf[‘AMPDBPASS’] = ‘password’;

Those will give you the values to insert into the user and pw variables in the script. YOU MUST INSERT THE CORRECT VALUES OR THE SCRIPT WILL NOT WORK! By the way, if you have both of the above-mentioned files, make sure that the AMPDBUSER and AMPDBPASS variables are set to the same respective values in both files, otherwise your CDR Reports page may not work.

Finally, if you want an e-mail notification when your IP address has changed, uncomment the two lines under “# OPTIONAL SEND EMAIL TO SYSTEM ADMINISTRATOR(S)” and modify the first line appropriately (make sure you use one or more valid e-mail addresses!). BE CAREFUL NOT TO DELETE THE TRAILING APOSTROPHE (just before the semicolon). Yeah, I did that once. 🙁

IF YOUR ARE RUNNING FREEPBX 12 (NOT FreePBX 14, see below), it appears they have changed the location where the IP address is stored in the database. In that case, two sections of the script need to be changed:

Change this:

		# GET IP ADDRESS FROM DATABASE
		my ($externip) = $connect->selectrow_array("SELECT data FROM sipsettings WHERE keyword like ?", undef, "externip_val");

To this:

		# GET IP ADDRESS FROM DATABASE
		my ($externip) = $connect->selectrow_array("SELECT val FROM kvstore WHERE `key` = ?", undef, "externip");

Change this:

						# IP HAS CHANGED SO UPDATE IP ADDRESS IN DATABASE
						$connect->do("UPDATE sipsettings SET data = ? WHERE keyword = ?", undef, "$ip", "externip_val");

To this:

						# IP HAS CHANGED SO UPDATE IP ADDRESS IN DATABASE
						$connect->do("UPDATE kvstore SET val = ? WHERE `key` = ?", undef, "$ip", "externip");

IF YOU ARE RUNNING FREEPBX 14, it appears they have changed the location again where the IP address is stored in the database. In that case, two sections of the script need to be changed:

Change this:

		# GET IP ADDRESS FROM DATABASE
		my ($externip) = $connect->selectrow_array("SELECT data FROM sipsettings WHERE keyword like ?", undef, "externip_val");

To this:

		# GET IP ADDRESS FROM DATABASE
		my ($externip) = $connect->selectrow_array("SELECT val FROM kvstore_Sipsettings WHERE `key` = ?", undef, "externip");

Change this:

						# IP HAS CHANGED SO UPDATE IP ADDRESS IN DATABASE
						$connect->do("UPDATE sipsettings SET data = ? WHERE keyword = ?", undef, "$ip", "externip_val");

To this:

						# IP HAS CHANGED SO UPDATE IP ADDRESS IN DATABASE
						$connect->do("UPDATE kvstore_Sipsettings SET val = ? WHERE `key` = ?", undef, "$ip", "externip");

(Thanks to “Tony” for posing the FreePBX 14 changes in the comment section.)

Regardless of which version you are running (12 or 14), BE CAREFUL, in both of the above lines the word keyword (without quotes) is changed to `key` (with backtick quotes). If you leave out the backticks, or change them to something else such as apostrophes, IT WILL NOT WORK.

Save your script to either the /root directory or the /var/lib/asterisk/agi-bin directory, or to another location of your choosing. I named it checkip.pl, solely because that was the name of a previous script I had run and I had already created a cron job for it. You must make the script executable, for example:

chmod u+rx /var/lib/asterisk/agi-bin/checkip.pl

Of course you will specify the correct filename and directory. Now it’s time to test the script. From the Linux command prompt, navigate to the directory where you stored the script:

cd /var/lib/asterisk/agi-bin

Now run the script from the command prompt:

./checkip.pl

Hopefully you won’t see any error messages. Remember it’s going out to do a query to get your external IP address, so don’t get concerned if it takes a second or two. If you had an incorrect address stored in your FreePBX Asterisk SIP Settings configuration, it will take longer because it will reload the FreePBX configuration. The script has a couple of different checks to make sure it only stores a real IP address (and not something invalid like an error message) in the database, so if it appears to not be working, make sure the underlying call to the web server or the dig command (depending on which variation you use) is returning a valid IP address.

Usually if you do see errors they will fall into one of two categories. The first is a missing Perl module, which you will need to obtain as described above. The second is a syntax error, which you should not get if you cut and pasted the script, and made the changes noted above. If you get a permissions error, you probably forgot to make the script executable!

Setting up a cron job:

Once it runs without errors, you will want to create a cron job so it runs automatically every five minutes. Do NOT run it more often than that, or the lookup service may ban your IP address, and you don’t want that to happen (whatismyip.com would do that, which is another reason not to use them), and besides, it’s not polite to hog the resources of someone else’s server! And if you are running it on multiple servers at the same IP address, then adjust the polling speed so that the total polling from all servers doesn’t exceed once every five minutes. An occasional additional test is probably not an issue, but if you try to poll every minute you just might get banned!

The usual way to add a cron job is to run this command:

crontab -e

(If you’re not currently running as root use sudo crontab -e instead)

This will open a text editor showing your current cron jobs. Just add a new line to the bottom of the file with your new cron job. To run the script every five minutes, you could use something like this:

*/5 * * * * /var/lib/asterisk/agi-bin/checkip.pl

Or to be more specific as to when the script runs (this will run it exactly on the hour, at five minutes after the hour, at ten minutes after the hour, and so on):

0,5,10,15,20,25,30,35,40,45,50,55 * * * * /var/lib/asterisk/agi-bin/checkip.pl

Just save the changed file when you are finished. The alternate method is to use Webmin’s System | Scheduled Cron Jobs module to set up your cron job.

Final testing:

The easiest way to test to make sure this is all working is to wait until a time that there are no active calls on the system, then go to the Asterisk SIP Settings configuration page and change the External IP address to something invalid (just change the last digit of the current address and Submit Changes, then do the usual orange bar reload). On the next five minute interval, the script should detect that the external IP address doesn’t match the one stored in the database, and it will write the correct value to the database and reload Asterisk. If you watch the Asterisk CLI during this time, you should actually see the reload take place. After that, if you go back to the Asterisk SIP Settings configuration page, the correct IP address should be there. To be extra safe, you should also view the contents of the file /etc/asterisk/sip_general_additional.conf and make sure that the externip= line shows the correct IP address.

Now you don’t have to worry about frantic calls from users at inopportune times because your ISP changed your IP address and none of the phones are working, and you also won’t have any of the problems associated with the Dynamic IP method!

I want to thank Moshe Brevda for giving me the information I needed to do the MySQL database write, after a particularly frustrating middle of the night session (not helped by bumping into a truly arrogant bastard on an IRC channel), and also for one correction to this article (see my comment in the comments section below). If any “Perl purists” are reading this and you want to offer a constructive comment without giving me any attitude, I’m fine with that. But if you are like some of your I-know-it-all-and-your-coding-sucks brethren in the IRC channel, don’t even waste your time posting a comment, because I won’t approve it. No, you really DON’T need to use any other Perl database modules to do this simple task, and no, I DON’T want to learn your philosophy of writing Perl code (there are some really sucky mom’s-basement-dwellers inhabiting the #perl IRC channel — some of those folks really need to get professional help, and that is all I will say about that). EDIT: Credit to the article Quickly Get an External IP Address from the Command Line (OS X Daily) for revealing the method of using dig with OpenDNS to get your IP address.

NOTE: As usual, there are no warranties — we’re experimenters here, and sometimes we don’t catch all the bugs, especially on the first go around! However, I would assume that anyone who is running a “professional” installation would pay their ISP for a true static IP address (one that never changes), and therefore wouldn’t need one of these scripts in the first place.