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.
IMPORTANT: When implementing any sort of restrictions on extensions, using the method described here or any other method, please be absolutely certain that you do not inadvertently restrict access to emergency services numbers (such as 911 in the U.S./Canada)!
There is a recurring question that comes up every so often, regarding how to give one particular extension (or a group of extensions) access to a different trunk for specific outgoing calls, or perhaps to restrict access to a particular trunk. Usually this involves an extension that is accessible to people that might want to make calls that cost money, and you don’t want them to do that. But there are many other reasons to route calls differently for different extensions, while still keeping all extensions on the same system so they can call each other.
Usually when someone asks about this, a common suggestion is to use the unsupported third-party Custom Contexts module. While this module is very versatile and lets you have a high degree of control over what each extension may access, there are at least two downsides. One is that it’s not part of the official distribution and therefore, a future upgrade of FreePBX might “break” it.
(This is probably less likely now, because it appears some of the FreePBX developers have taken an interest in maintaining it, but it’s still not beyond the realm of possibility.)
The other issue is that you have to go through and check (and maybe change) all the priority dropdowns if you add, remove, or move a route, and that can get to be a pain in the butt very quickly if you are in the habit modifying your routes with any frequency.
The problem with this page is that although it discusses several alternatives to using Custom Contexts (and you may wish to read it just to learn about those other possibilities), it is getting rather dated and therefore does not mention the use of the fourth field in Outbound Routes, a.k.a the “CallerID” field, which is by far the easiest way to implement this.
Let’s say you have an existing outbound route, over which your outbound calls normally travel, and it has a particular selection of trunks. But you also have an extension, let’s say it’s extension 234, and you want it to use a different trunk or group of trunks. In FreePBX 2.9 or later, all you have to do is this:
Go to the settings page for the Outbound Route that is currently used for outgoing calls.
At the bottom of the page, next to the “Submit Changes” button, there is a new “Duplicate Route” button. Click on “Duplicate Route”.
Move the duplicated route to be higher in priority than the original route (it should appear just above the original route in the right-hand column).
Optionally rename the duplicated route to something more to your liking.
In the duplicated route, under “Dial Patterns that will use this Route“, add the extension number (or pattern matching a group of extensions) to the fourth (CallerID) field of EVERY dial pattern on the list. Or, if using the Swiss Army Knife Module and you have checked the “Turn On Old (Pre 2.8) Dial Plan Textbox” checkbox (EDIT: or if you have FreePBX 12 or later, and under Settings | Advanced Settings, in the “GUI Behavior” section you have set Enable The Old Style FreePBX Dial Patterns Textarea to True), then add the extension number or pattern to the end of every existing pattern, separated by a forward slash. As an example, an existing pattern of 1+NXXNXXXXXX would become 1+NXXNXXXXXX/234. Again, you must do this to every pattern in the pattern list.
And finally, in the duplicated route, change the the “Trunk Sequence for Matched Routes” to include only those trunks that you want that extension or group of extensions to use.
If there are additional Outbound Routes for which you want to change the trunk selection for the same extension, repeat the above, starting with the other outbound route(s). If you have additional extensions and you want one or more of them to have different trunk usage, repeat the above, using the different extension number(s) in the CallerID field and the different trunk selections.
If you want to block an extension’s ability to make toll calls, use the same procedure but only give them access to an ENUM trunk. ENUM is pretty broken then days, it it would be rare for a call to actually complete, but if it does it’s not going to cost you anything. This particular usage is discussed in more detail in “How to block a single extension’s ability to make outgoing toll calls in FreePBX“. (EDIT: In the most recent versions of FreePBX you can simply 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.)
And again, please note that you can use a single extension number OR a pattern in the CallerID field. For example, if you had a pattern like 1NXXNXXXXXX, you could do something like:
1NXXNXXXXXX/100 – match on the pattern only if the call is from extension 100
1NXXNXXXXXX/2[45]X – match on the pattern only if the call is from an extension in the range 240-259
1NXXNXXXXXX/3XX – match on the pattern only if the call is from an extension in the range 300-399
And if you wanted to allow the call only if it came from extension 100, 240-259, or an extension in the 300’s then you could use all three of the above rules in the same outbound route.
I will offer my opinion that using the Swiss Army Knife Module and checking “Turn On Old (Pre 2.8) Dial Plan Textbox” is the only way to go if you happen to have several hundred dial patterns! Well, maybe not the only way (you could export a .CSV file, edit it, and import it back in), but definitely the easiest, because you can simply cut all the patterns from the textbox and paste them into a text editor, then use search-and-replace to add the extension numbers, then copy the changed patterns from the text editor and paste them back into the textbox in the Outbound Route. If the search-and-replace function supports regex matching then it’s easy – set the find string to n and set the replace string to /234n (assuming 234 is the extension number you want to add), and replace all occurrences (be sure to check the first and last lines to make sure they look as they should, in case there was a missing or extra newline character somewhere).
EDIT: We have been informed that the old-style textboxes are once again available in FreePBX 12 and later. You have to click on the Settings tab, then Advanced Settings, then find the “GUI Behavior” section and change the Enable The Old Style FreePBX Dial Patterns Textarea setting to True.
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:
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.
4. In your ORIGINAL emergency 911 Outbound Route, change the trunk selection to use only the CUSTOM trunk you created in step 2.
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.
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:
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.
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.
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
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?”
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):
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:
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.
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.
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!
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.
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:
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:
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):
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.
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.
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:
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.
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).
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.
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.
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:
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):
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.
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 July, 2011. This functionality may or may not be already present in newer versions of FreePBX.
NOTE: If you have installed a separate FreePBX CDR report tool module and it does not already include this functionality, you may need to do this before you follow these instructions: Copy this article (starting with the paragraph just before “[custom-from-trunk-accountcode]”) and paste it into a text editor, then use the editor’s search-and-replace to search for the string “accountcode” and change every occurrence of it to “did” (without the quotes in both cases), and follow those instructions. That way you’ll be saving your DID information to the did field created in the CDR database by the module. I cannot tell you if you need to do this or not, because the last version of FreePBX I used was 2.9, and I have no plans to upgrade.
Another thing I am posting just so I can find it later…
Many people have wished for a way to see the source DID in FreePBX call detail reports. It turns out there is a pretty easy way to do it IF you are not using Account Codes in your system, and have no plans to do so. Many FreePBX users never use account codes so the following method will work for them.
Asterisk stores its CDR data in /var/log/asterisk/cdr-csv/Master.csv. If you know the format in which it stores its data, you realize that the first field, accountcode, isn’t used on most systems. Since Asterisk currently doesn’t store the source DID for a call, we can repurpose the accountcode field to store our source DID information.
So, there are two things that need to be done. The first is to get the DID into the accountcode and to do that, we simply add a new context to /etc/asterisk/extensions_custom.conf as follows:
NOTE: The above assumes that all your DID’s are entirely numeric. It will fail (and calls may not reach your inbound routes) if you do not first strip off any non-numeric characters, or change the context to accept them. For example, if a provider sends a + at the start of the DID (NOT the Caller ID, which is more common), then try changing both occurrences of _X! to _[+X]!
Then for each of our trunks, we go into FreePBX and change the context= line from context=from-trunk to:
context=custom-from-trunk-accountcode
If by some chance you are already sending calls from one or more of your trunks to a custom context in extensions_custom.conf rather than from-trunk, you can simply add one of the following lines to that custom context. If you add it as the first line, use:
exten => _X!,1,Set(CDR(accountcode)=${EXTEN})
And make sure that any subsequent line is not also numbered “1”. If it’s NOT the first line, use:
exten => _X!,n,Set(CDR(accountcode)=${EXTEN})
That should get your DID into the accountcode field of /var/log/asterisk/cdr-csv/Master.csv
To actually display the field, I refer you to this article on the PSU VoIP blog:
Read that article and the comments underneath, because it explains the principle of displaying additional fields in the FreePBX CDR. This is how I set up my /etc/asterisk/call-log-table.php file:
calldate", "10%", "center", "SORT", "19");
$FG_TABLE_COL[]=array ("Source Channel", "channel", "14%", "center", "", "32");
$FG_TABLE_COL[]=array ("Source DID", "accountcode", "10%", "center", "SORT", "20");
$FG_TABLE_COL[]=array ("Source", "src", "10%", "center", "SORT", "30");
$FG_TABLE_COL[]=array ("CLID", "clid", "20%", "center", "", "80",'','','','',
'','filter_html');
$FG_TABLE_COL[]=array ("Dest.", "dst", "10%", "center", "SORT", "30");
$FG_TABLE_COL[]=array ("Dest. Channel", "dstchannel", "14%", "center", "", "32");
$FG_TABLE_COL[]=array ("Disposition", "disposition", "6%", "center", "", "30");
if ((!isset($resulttype)) || ($resulttype=="min"))
$minute_function= "display_minute";
$FG_TABLE_COL[]=array ("Duration", "duration", "6%", "center", "SORT", "30",
"", "", "", "", "", "$minute_function");
$FG_TABLE_DEFAULT_ORDER = "calldate";
$FG_TABLE_DEFAULT_SENS = "DESC";
// This Variable stores the argument for the SQL query
$FG_COL_QUERY='calldate, channel, accountcode, src, clid, dst, dstchannel, disposition,
duration';
$FG_COL_QUERY_GRAPH='calldate, duration';
// The variable LIMITE_DISPLAY define the limit of record to display by page
$FG_LIMITE_DISPLAY=25;
// Number of column in the html table
$FG_NB_TABLE_COL=count($FG_TABLE_COL);
// The variable $FG_EDITION define if you want process to the edition of the
// database record
$FG_EDITION=true;
//This variable will store the total number of columns
$FG_TOTAL_TABLE_COL = $FG_NB_TABLE_COL;
if ((isset($FG_DELETION) && $FG_DELETION) || $FG_EDITION)
$FG_TOTAL_TABLE_COL++;
//This variable define the Title of the HTML table
$FG_HTML_TABLE_TITLE=" - Call Logs - ";
//This variable define the width of the HTML table
$FG_HTML_TABLE_WIDTH="100%";
?>
As always you should copy and paste the code, so you get complete lines including anything that WordPress truncates on the display.
The above shows the Source DID column just to the right of the Source Channel column. I also made Source DID a sortable column, so you can show your usage by DID by clicking on the “Source DID” column heading.
At the start I said that you can only use this if you’re not using Account Codes on your system. Actually, that may not be strictly true. A DID would normally only be saved for an incoming call, while an Account Code would normally only be saved for an outgoing call. So, it may be possible to make that field do double duty, but since I don’t use Account Codes and don’t know anyone who does, I’ll leave that as an exercise for the reader.
Recent Comments