Switching to a software PBX, Part 2

January 1, 2009; updated January 2011

InPart 1 we talked about the connection of the handset to the Asterisk server, going over OpenVPN. That task did involve quite a bit of configuration work: installing and configuring OpenVPN, making the IP connection and configuring the handset to link to Asterisk. Now we complete the other half of the problem: connecting Asterisk to Broadvoice (our current SIP trunk provider) and making all of it provide useful extensions and voicemail. Later articles may cover more advanced features, such as linking Asterisk to our CRM system. Wouldn't it be cool if your customer's profile comes up on your web browser when the phone rings, based on the customer's caller ID? Asterisk can be linked to your CRM system to make that happen. But the first step is to get the basic PBX working.

We'll show these steps starting with connecting to our SIP provider (Broadvoice, in this example), then going on to adding extensions and services. In reality, you would do it in the reverse order: get all the services working on the handset, test everything, and then configure the dial-in to work. We're using Asterisk 1.4 in this article. The configuration will be similar for other versions.

Objectives

We want to provide a typical PBX system that small businesses expect today:

All of this is "standard stuff" for a small business PBX. Asterisk and SIP phones can do all of it.

Before you begin, you'll need to:

Connecting to the SIP trunk

The trunk is what gets us to the PSTN. Here's the diagram from Part 1:

Please install a SVG plugin for your browser, or use Firefox to view this image.

In this case, we're using Broadvoice as our SIP trunk. Any others would also work in a similar way, and when we're done, it will be clear that it's easy to switch the trunk provider with minimal configuration changes.

Before starting, it is necessary to get Broadvoice to enable Asterisk on the account. Call their customer service number and ask for Asterisk setup and a SIP password. Other SIP trunks may have different procedures.

The trunk is defined in /etc/asterisk/sip.conf. In the general section, add this line:

register => 3103567869@sip.broadvoice.com:password:3103567869@sip.broadvoice.com/incoming

Of course our number is 310 356 7869. Use your number. password is the secret password you got from Broadvoice.

Then add a context in sip.conf:

[sip.broadvoice.com]
type=peer
user=phone
; note that we must configure this domain name in /etc/hosts
host=sip.broadvoice.com
fromdomain=sip.broadvoice.com
fromuser=3103567869
secret=password
; note that we use the ten-digit phone number, without the country code
username=3103567869
; insecure=very no longer exists in Asterisk 1.6.
; insecure=very
insecure=invite,port
context=from-broadvoice
authname=3103567869
dtmfmode=inband
dtmf=inband

Again, use your password and your phone number.

One more change is necessary. Add an entry into /etc/hosts to define sip.broadvoice.com. See their website; you'll need to pick the best of their proxies for your location.

Turn off any other devices you have that connect to Broadvoice. If they sent you a Sipura or something like that, turn it off. They do not allow more than one device to be active on a line at the same time.

Now there should be a SIP connection to Broadvoice. We need to do something with it.

A "hello world" dialplan

Note the line context=from-broadvoice. This means that any incoming call on that SIP connection will go to the from-broadvoice context within /etc/asterisk/extensions.conf. extensions.conf is where we will be doing 95% of our configuration. Let's add a from-broadvoice context. Edit extensions.conf and add:

[from-broadvoice]
exten => 3103567869,1,Answer()
exten => 3103567869,n,Playback(hello-world)
exten => 3103567869,n,Hangup()

In all these examples, substitute your phone number where we have 3103567869. When the Broadvoice SIP line calls in, it goes to the Broadvoice phone number as its extension. We've created a simple dial plan which answers, plays "hello world", and hangs up.

Test it by dialing in from a regular phone. You'll hear Allison saying "hello world".

Where is the file? It's /usr/share/asterisk/sounds/hello-world.gsm. Asterisk looks in the /usr/share/asterisk/sounds directory if the full path is not specified, and it looks for files with extensions it knows. These include GSM and WAV and perhaps others, depending on configuration.

Now we have incoming calls reaching Asterisk, and in Part 1, we had SIP phones reaching Asterisk, so we're ready to start the fun part: making the dialplan do useful things.

Presenting the voice menu

I won't re-cover everything in the Asterisk manual. I will only go over the configuration briefly. Read the manual to understand in detail what is going on.

We're editing extensions.conf, which is the file that defines the dial plan. First, add global variables for SIP references. These are a more convenient way to refer to them later in the dial plan:

[globals]
; skipped
JOE=SIP/joe

joe refers to the SIP context in sip.conf.

Here is our complete from-broadvoice context, which presents the voice menu:

[from-broadvoice]
; you can put more extensions into a separate context
; called staff-incoming, and include it here, to make
; this file easier to edit
; include => staff-incoming

exten => 3103567869,1,Answer()
exten => 3103567869,n,Background(custom/regular-hours-message)
exten => 3103567869,n,WaitExten(15)
exten => 3103567869,n,Hangup()

; Define ext. 101 with music-on-hold
exten => 101,1,Dial(${JOE},22,m)
exten => 102,n,VoiceMail(101@default,u)
exten => 103,n,Hangup()

You'll also need to edit voicemail.conf to define mailbox 101. I also added a definition for Pacific timezone and changed some other voicemail settings in that file. I configured it to email out the voicemails, making it even more convenient to listen to them and forward them.

Internal calls

Now we need to set up a context to allow our staff to make internal calls. We call it staff and it has extensions just like the incoming plan. In fact, both the incoming and staff extensions could be put into one context, and then shared using include. Note that staff is the context specified for the SIP phone in the sip.conf file. That's how SIP extensions come into the dial plan.

We add one more thing in the staff context:

exten => 800,1,VoiceMailMain()

This lets staff, who have come in over the VPN, access the voicemail system. Note that by placing that in the staff context, we are not letting the voicemail system be accessed by anyone calling in from an external line. For some, that might be too restrictive. For us, we treat our voicemail with the same security we treat email, namely, all access must be encrypted and secure. The PSTN is neither so it is not acceptable (to us) for voicemail.

Outbound calling

Add two includes to the staff context:

include => fraud
include => outbound

We'll get to the fraud context later. outbound is simple:

exten => _9NXXXXXXXXX,1,Dial(${OUTBOUNDTRUNK}/${EXTEN:1})
exten => _9NXXXXXXXXX,n,Hangup()

This uses pattern matching to let internal users dial 9 to pass calls through to the outbound trunk. This is what the outbound trunk variable looks like in the globals section of extensions.conf:

OUTBOUNDTRUNK=SIP/sip.broadvoice.com

The sip.broadvoice.com string does not refer to a DNS name. Rather, it refers to the context block in sip.conf.

What is the fraud context we have included?

Preventing outgoing call fraud

The North American Numbering Plan is our familiar 3+7 dial plan: 310-356-7869. 310 is the area code. Note that the US is not the only country in the NANP. All of Canada can be reached with the same 3+7 dial format, without dialing any international calling prefix. Calling Canada is fine because their telco regulations provide good consumer protection, and rates to call Canada are similar to long-distance rates in the US (our calls to Canada from Broadvoice are free).

The NANP also covers a dozen or so countries in the Caribbean. These calls don't require any international dialing code like 011+country code. They look just like ordinary 3+7 phone numbers, and with all the new extensions in the US, you could easily be dialing an area code without knowing where it is.

This is a problem because these countries do have expensive international calling rates. Worse, their telco regulations allow "premium" numbers to be created without any distinguishing prefix, such as the US' 900 numbers. It's possible to call a Caribbean number and be billed $25 / minute. Many scams try to induce people to dial these numbers for various reasons. There is no way to fight the charges when this happens, because they were billed under the laws of a foreign country.

Unfortunately, the consequence of this is that, unless your business makes regular calls to the Caribbean, it's better to block all outgoing calls to all the Caribbean countries that are within the NANP. Exceptions can be added as needed. How often do your employees have a business need to call up the Turks and Caicos? Not often enough to not block it at the PBX level. Further, many of these countries offer off-shore casinos and bookies. It's unacceptable for employees to call such numbers. Therefore, we block.

This is our fraud context, which, when included as we showed above, blocks calls to 900 numbers (premium numbers) and all the NANP countries in the Caribbean:

[fraud]
; START OF FRAUD BLOCKS
; Old Caribbean code for all countries - 809
exten => _9809XXXXXXX,1,Playback(not-auth-pstn);
exten => _9809XXXXXXX,n,Hangup()

; Anguilla
exten => _9264XXXXXXX,1,Playback(not-auth-pstn);
exten => _9264XXXXXXX,n,Hangup()

; Antigua and Barbuda
exten => _9268XXXXXXX,1,Playback(not-auth-pstn);
exten => _9268XXXXXXX,n,Hangup()

; Bahamas
exten => _9242XXXXXXX,1,Playback(not-auth-pstn);
exten => _9242XXXXXXX,n,Hangup()

; Barbados
exten => _9246XXXXXXX,1,Playback(not-auth-pstn);
exten => _9246XXXXXXX,n,Hangup()

; Bermuda
exten => _9441XXXXXXX,1,Playback(not-auth-pstn);
exten => _9441XXXXXXX,n,Hangup()

; British Virgin Islands
exten => _9284XXXXXXX,1,Playback(not-auth-pstn);
exten => _9284XXXXXXX,n,Hangup()

; Cayman Islands
exten => _9345XXXXXXX,1,Playback(not-auth-pstn);
exten => _9345XXXXXXX,n,Hangup()

; Dominica
exten => _9767XXXXXXX,1,Playback(not-auth-pstn);
exten => _9767XXXXXXX,n,Hangup()

; Dominican Republic
exten => _9829XXXXXXX,1,Playback(not-auth-pstn);
exten => _9829XXXXXXX,n,Hangup()

; Grenada
exten => _9473XXXXXXX,1,Playback(not-auth-pstn);
exten => _9473XXXXXXX,n,Hangup()

; Montserrat
exten => _9664XXXXXXX,1,Playback(not-auth-pstn);
exten => _9664XXXXXXX,n,Hangup()

; Saint Lucia
exten => _9758XXXXXXX,1,Playback(not-auth-pstn);
exten => _9758XXXXXXX,n,Hangup()

; St. Vincent and the Grenadines
exten => _9784XXXXXXX,1,Playback(not-auth-pstn);
exten => _9784XXXXXXX,n,Hangup()

; Trinidad and Tobago
exten => _9868XXXXXXX,1,Playback(not-auth-pstn);
exten => _9868XXXXXXX,n,Hangup()

; Turks and Caicos
exten => _9649XXXXXXX,1,Playback(not-auth-pstn);
exten => _9649XXXXXXX,n,Hangup()

; US Virgin Islands
exten => _9340XXXXXXX,1,Playback(not-auth-pstn);
exten => _9340XXXXXXX,n,Hangup()

; Jamaica
exten => _9876XXXXXXX,1,Playback(not-auth-pstn);
exten => _9876XXXXXXX,n,Hangup()

; St. Kitts and Nevis
exten => _9869XXXXXXX,1,Playback(not-auth-pstn);
exten => _9869XXXXXXX,n,Hangup()

; premium numbers
exten => _9900XXXXXXX,1,Playback(not-auth-pstn);
exten => _9900XXXXXXX,n,Hangup()

That blocks all the NANP countries in the Caribbean, and it blocks 900 numbers. Test to make sure; dial a number in 809 (like 809 333 4444) from an internal line, and you should get the not-auth-pstn sound file.

Note that we have not configured any other international dialing. We can add countries as needed. Further, we could create an international-outgoing context if we wanted to, to give different staff different levels of calling access. We can define countries individually, or individual area codes or specific numbers that are reachable or unreachable. We can use Asterisk this way to create a "telecom firewall".

I apologize to the citizens of the Caribbean, who have been summarily blocked by our firewall rules. If the Caribbean countries want to be taken off the list, they should:

Securing internal context access

We should configure Asterisk to not allow connections in the staff context except from SIP devices which are bound to the OpenVPN address. That address is on a non-routing subnet (10.*.*.*), so outside hosts can never connect to it. OpenVPN uses public-key based security, and can also work with firewalls for even more restrictions. Limiting dial-out to only OpenVPN-connected lines makes a lot of sense. We can do this by specifying a bind address in the sip.conf context:

[joe]
; .... other settings
bindaddr = 10.8.0.1

Doing this means that connections to that SIP context can only come on the 10.8.0.1 interface, which is the OpenVPN VPN endpoint.

Conclusion

After much configuration, we have a very basic dial plan that provides our PBX, with extensions, voicemail, and the security features we want. It's great.

But it's just the beginning. What else can we do?

What else is in the future? Asterisk was the first full-featured open source PBX, but now, there is another: JBoss Mobicents. This is an open-source JSLEE container for building SIP applications. And the company that supports it is now owned by RedHat. We will, in future, explore Mobicents, and perhaps switch to it. The main attraction for us is we are a Java and JBoss shop, and we would like to have our PBX integrated with our other Java servers.