Asterisk, and other worldly endeavours.

A blog by Leif Madsen

Posts Tagged ‘howto

Using Dialplan Functions: AES_DECRYPT() and AES_ENCRYPT()

I  recently asked on twitter how many people would be interested in a set of blog posts that focused on how to use the various dialplan functions in Asterisk, and I got quite a positive response. I posted that shortly before getting married, and now that I’m back into the groove of things, I’m going to take a shot at posting a bunch of content focused around Asterisk dialplan functions. If you don’t know what Asterisk dialplan functions are, head on over to the online version of Asterisk: The Definitive Guide (3rd edition) (or buy it) and read the section on dialplan functions. If you’re still starting out with Asterisk, I highly suggest you start with the dialplan basics chapter.

Today we’ll look at the first 2 dialplan functions in my list: AES_DECRYPT() and AES_ENCRYPT()

The AES_DECRYPT() and AES_ENCRYPT() functions work by passing strings to the functions, and they return a result. If you pass an unencrypted string to the AES_ENCRYPT() function it will return an encrypted string; vice-versa for the AES_DECRYPT() function. The two functions operate by passing a string and a key where the result is encoded  in base64.

Use case for these functions probably makes the most sense when you need to store data outside of the dialplan, perhaps passwords, pins, or other data passed in by the caller, but which you want to secure when you go to store it. Let’s take an example where we create some dialplan that allows a caller to set their pin and store it in the database. For the sake of simplicity I’m not going to add any error checking (like to verify we really have data to work with, allow the caller to verify their extension, etc.):

exten => *88,1,NoOp()
 same => n,Playback(silence/1)
 same => n,Read(UserExtension,extension,3)                  ; read persons 3 digit extension unmber
 same => n,Verbose(2,Extension number: ${UserExtension})
 same => n,Read(PinEntry,agent-pass)                        ; ask for a pin number
 same => n,Verbose(2,Pin number: ${PinEntry})
 same => n,SayDigits(${PinEntry})                           ; say pin back to caller
 same => n,Set(DB(pin/${UserExtension})=${PinEntry})        ; store pin in the AstDB
 same => n,Playback(vm-goodbye)
 same => n,Hangup()

After the user enters their extension and pin, we store it in the AstDB. We can verify it was stored correctly by checking from the Asterisk CLI:


scrappy*CLI> database show pin
/pin/100 : 1234
1 results found.

Now let’s modify our dialplan to store the pin in the database using a value returned from AES_ENCRYPT().

exten => *88,1,NoOp()
 same => n,Playback(silence/1)
 same => n,Read(UserExtension,extension,3)
 same => n,Verbose(2,Extension number: ${UserExtension})
 same => n,Read(PinEntry,agent-pass)
 same => n,Verbose(2,Pin number: ${PinEntry})
 same => n,SayDigits(${PinEntry})
 same => n,Set(SpecialKey=1234qwerasdfzxcv)
 same => n,Set(EncryptedPin=${AES_ENCRYPT(${SpecialKey},${PinEntry})})
 same => n,Set(DB(pin/${UserExtension})=${EncryptedPin})
 same => n,Playback(vm-goodbye)
 same => n,Hangup()

And we can see the encoded string stored in the database:


scrappy*CLI> database show pin
/pin/100 : Je2G/qyHuGVKgvvXDwXjHA==
1 results found.

Of course anyone who has access to the AstDB from the Asterisk CLI is also going to have access to the Asterisk dialplan, so you’ll have to do a better job than I have here of hiding the secret key being used for encrypting the data. Really all we’re trying to do here is not make the list of pins and data in our AstDB quite so obvious. We could of course not use AstDB at all, and store the data remotely where we know people will have access to the data, but not access to the secret key on our Asterisk server.

Now lets look at the inverse by decoding the pin to authenticate someone.

exten => *77,1,NoOp()
 same => n,Playback(silence/1)
 same => n,Read(UserExtension,extension,3)                     ; get users extension
 same => n,Set(EncryptedPin=${DB(pin/${UserExtension})})       ; get encrypted pin from AstDB
 same => n,Read(PinEntry,agent-pass)                           ; get pin from user
 same => n,Set(SpecialKey=1234qwerasdfzxcv)
 same => n,Set(DecryptedPin=${AES_DECRYPT(${SpecialKey},${EncryptedPin})})                          ; decrypt the pin
 same => n,Playback(${IF($["${PinEntry}" = "${DecryptedPin}"]?pin-number-accepted:pin-invalid)})    ; if pin is correct, play number accepted, else, pin invalid
 same => n,Playback(vm-goodbye)
 same => n,Hangup()

That’s it for now. Leave a comment if you like this format, and if you found this article useful. Thanks!

Written by Leif Madsen

2011/09/09 at 8:28 am

Scheduling automated calls between two participants with res_calendar

Here is a little dialplan snippet I wrote this morning for the next edition of the Asterisk book. While I’m not going to delve into all the aspects of setting up res_calendar like we do in the book, I thought for those of you who might already have this working might enjoy it.

(The calendaring modules are available in Asterisk 1.8, which is currently in release candidate status. Check out http://www.asterisk.org/downloads for the current version.)

I started with this little bit of dialplan that gets triggered when a call is answered from the calendaring module:



[AutomatedMeetingSetup]
exten => start,1,Verbose(2,Triggering meeting setup for two participants)
   same => n,Set(DeviceToDial=${FILTER(0-9A-Za-z,${CALENDAR_EVENT(location)})})
   same => n,Dial(SIP/${DeviceToDial},30)
   same => n,Hangup()

The location field in my calendar event (which in this case is labeled as Destination in my Google Calendar) contains the string 0000FFFF0002 which is the device identifier in my example.

Once you get that working, the cool magic happens below. In the following example, a call is placed from the calendaring module when a meeting needs to take place between two participants. The first part of the dialplan allows the first person called to accept or reject the meeting, and if accepted, to record a message for the other party. Once that recording is saved, the dialplan will go ahead and trigger a call to the other meeting participant.

When that meeting participant answers the call, a Macro() is employed to allow them to listen to the recorded message left by the first party, (i.e. “Hey Jim, this is Leif. We have a meeting scheduled right now.”). That person is then presented the same option to accept or reject the call by pressing 1 or 2.

Of course the dialplan could even by further expanded to play back messages when the calls were rejected, the option for the called party to leave a return message of why they are rejecting the call, and maybe even the ability to post-pone the call for a few minutes. All it takes is some clever dialplan!

[AutomatedMeetingSetup]
exten => start,1,Verbose(2,Triggering meeting setup for two participants)
same => n,Read(CheckMeetingAcceptance,to-confirm-wakeup&press-1&otherwise&press-2,,1)
same => n,GotoIf($["${CheckMeetingAcceptance}" != "1"]?hangup,1)

same => n,Playback(silence/1&pls-rcrd-name-at-tone&and-prs-pound-whn-finished)
same => n,Set(__RandomNumber=${RAND()})
same => n,Record(/tmp/meeting-invite-${RandomNumber}.ulaw)

same => n,Set(DeviceToDial=${FILTER(0-9A-Za-z,${CALENDAR_EVENT(location)})})
same => n,Dial(SIP/${DeviceToDial},30,M(CheckConfirm))
same => n,Hangup()

exten => hangup,1,Verbose(2,Call was rejected)
same => n,Playback(vm-goodbye)
same => n,Hangup()

[macro-CheckConfirm]
exten => s,1,Verbose(2,Allowing called party to accept or reject)
same => n,Playback(/tmp/meeting-invite-${RandomNumber})
same => n,Read(CheckMeetingAcceptance,to-confirm-wakeup&press-1&otherwise&press-2,,1)
same => n,GotoIf($["${CheckMeetingAcceptance}" != "1"]?hangup,1)

exten => hangup,1,Verbose(2,Call was rejected by called party)
same => n,Playback(vm-goodbye)
same => n,Hangup()

Written by Leif Madsen

2010/09/29 at 9:25 am

Asterisk IMAP and Gmail

Today I was working on the next edition of the Asterisk book and wanted to see if I could get Asterisk IMAP voicemail support to work with Gmail. I had tried doing this a few times in the past without success, but since I had spent some time documenting and testing against Dovecot last week for another client and gotten everything working, I figured I had a good base to start trying to connect to the Gmail IMAP servers.

At first I was having problems with getting Asterisk to connect to the server as it would keep timing out when trying to connect to the Gmail IMAP servers on port 993. I looked at the instructions for connecting and double checked, and I thought I had everything right. I also made sure my IMAP library was compiled with OpenSSL support since Gmail requires you to connect via SSL.

After reading a few emails and doing more testing, I finally stumbled upon the missing link! Find below the snippet of voicemail.conf configuration that finally allowed me to connect to the Gmail IMAP system with Asterisk IMAP voicemail support.

Note: Be aware that there is a mixture of commas and pipes in the line where we’ve setup mailbox 100. This is not a typo!

; voicemail.conf
imapserver=imap.gmail.com
imapport=993
imapflags=ssl

pollmailboxes=yes
pollfreq=30

[default]
100 => 100,Leif Madsen,,,attach=no|imapuser=leif.madsen@MYDOMAIN_GOOGLE_APPS.com|imappassword=my_secret_password

I was using this with Google Apps for one of the domains we bought for working on the book, so the login is the full email address. The password is what you use for logging into the Gmail interface. Also, you need to make sure you’ve enabled IMAP support in the web interface before trying this or else your connection won’t work.

More information including step-by-step instructions on compiling IMAP support into Asterisk and configuration examples for Dovecot and Gmail will be in the upcoming book, but I was so excited to get this working today that I thought I’d share the secret sauce at least so you don’t have to wait for the whole recipe.

Connecting to Gmail was not as quick as connecting to Dovecot on a remote server I was working with. I imagine this is due to the high load Google has to deal with, so while it works, there may be some minor delays when retrieving and leaving voice messages, but nothing that caused it to be unusable.

Note: The KEY to making it work was the imapflags=ssl part. Without that you won’t get connected and will have problems with timeouts and such going on with Asterisk. Once I enabled the ssl flag I was golden.

Written by Leif Madsen

2010/09/20 at 10:37 am

Posted in Asterisk

Tagged with , , , , , , ,

Installing the Asterisk Test Suite

In case you missed it, I wrote an introductory article about the Asterisk Test Suite on the Asterisk blog. The post takes you from a minimally installed Ubuntu 9.10 up to the point that you can run the tests in the test suite by going through all the possible errors you might encounter getting it loaded, and how to resolve those errors (most of them being missing dependencies).

Enjoy!

http://blogs.asterisk.org/2010/04/29/installing-the-asterisk-test-suite/

Written by Leif Madsen

2010/05/03 at 10:17 am

Using a Nokia E71 with Asterisk (3G or WiFi)

There was some talk in one of the IRC chat rooms today about someone trying to get their E61i working with Asterisk. I haven’t had an issue getting that phone or my E71 phone working, but regardless he was having issues. I figured I might as well spend a little bit of time today going through my configuration, both for my own reference, and so that other people can get their Nokia’s setup with Asterisk as well.

I’ll be using the native SIP client, although I’ve had just as good of luck using the Fring application. The advantage to the Fring application is that you can use it with Skype, along with multiple IM clients, and also video! I especially like that the application makes use of the video camera on the front of the phone so that you can use it as a videophone. Using the video on a phone like the iPhone or Nexus One seems useless to me (but I digress!).

First, lets get our Asterisk configuration setup in sip.conf. We’ll need to make sure we’ve setup a realm in sip.conf as our phone will require it. If you don’t, then the default realm is ‘asterisk‘.

sip.conf:

[general]
realm=pbx.my_asterisk_box.com
disallow=all
allow=ulaw
allow=alaw
srvlookup=yes
pedantic=yes
maxexpiry=360
minexpiry=120
defaultexpirey=120
videosupport=yes

[leifmadsen_cell]
type=friend
secret=super_secret_password
context=devices
nat=yes
canreinvite=no
qualify=no
mailbox=100@default
callerid=Leif Madsen <571>
insecure=invite,port
subscribecontext=subscriptions
disallow=all
allow=g729
allow=ulaw
Feel free to change or add whatever options you need for your sip.conf. This is generally what I have working right now. I’ve left out all my domain handling and SIP URI stuff this time around. Maybe I’ll talk about it in another blog post in the future.
OK, back to the task at hand. Now that we have our sip.conf file configured, just run ‘sip reload’ from the Asterisk console, and your settings should be available. You can check to make sure your peer loads up with ‘sip show peers‘ or ‘sip show peer leifmadsen_cell‘ (or whatever you called your configuration.
The next step up is to configure our Nokia device. These settings should likely be the same on both the E61i and the E71, but I’m working from a 400 series firmware on the E71, so your mileage may vary.
Menu > Tools > Settings > Connection > SIP Settings > Options > New SIP Profile > Use default profile

With the new profile created, we need to modify it for connection to our Asterisk system. Starting at the top we have the following fields: Profile name, Service profile, Default access point, Public user name, Use compression, Registration, Use security, Proxy Server, and Registrar Server. We’ll going through each of these and configure the two submenus: Proxy Server and Registrar Server.
Profile name: Anything you want. I called mine “Business Line”
Service profile: IETF
Default access point: Select either a wifi connection or 3G connection. In my case I’m selecting “Rogers Internet”
Public user name: sip:leifmadsen_cell@pbx.my_asterisk_box.com (notice how leifmadsen_cell is the same as what we configured in sip.conf)
Use compression: No
Registration: Always on (you can set this to ‘When needed’ if you only want to place outbound calls via VoIP sometimes)
Use security: No
Proxy Server >
Proxy server address: pbx.my_asterisk_box.com
Realm: pbx.my_asterisk_box.com
Username: leifmadsen_cell
Password: super_secret_password
Allow loose routing: Yes
Transport type: UDP
Port: 5060 (unless you’ve changed this yourself on your Asterisk box)
Back > Registrar server >
(fill this information out exactly like the Proxy server section)
At this point, hit the Back button a couple of times to make sure you phone will register. If you’re still having issues, double check all your configuration options, and potentially restart the phone. With older firmware versions I’ve had issues where if I don’t get it perfect the first time and make a change, I have to restart the phone.
Once we see that we’ve registered the device, we need to enable it from another screen so that we can place and receive calls from Asterisk.
Go back out of the SIP Settings screen to your Connection screen in the Tools menu, then select Internet tel.
By default you will see a screen that says (no Internet telephone settings).
Select the Options button and create a new profile. There will be two fields: Name and SIP profiles. By default the SIP profile field should be selected with Business Line (or whatever you called your SIP connection) automatically. The Name field is currently set to Default, but I just renamed it to VoIP. Feel free to name it anything you want.
Back out of all your menus until you get back to the main screen. You should see an icon in the upper-right hand corner that looks like a telephone hand set on top of a globe. At this point, try dialing one of the extensions on your Asterisk server to see if things are working! I like to try calling my voicemail as it lets me test DTMF as well.
Below is a (modified) INVITE from the E71 showing what you’ll see when the request comes from the phone. The most interesting part is the SDP portion which shows us which codecs the device supports and offers. In the case of the phone and firmware combination I’m using, I can use G.711 ulaw and alaw, G729, and iLBC.
INVITE sip:8500@pbx.my_asterisk_server.com;user=phone SIP/2.0
Route:
Via: SIP/2.0/UDP 10.10.10.84:5060;branch=z9hG4bKlq60dckmalhc6vap06nosen;rport
From: ;tag=mh5gdciapphc6m6506no
To:
Contact:
Supported: 100rel,sec-agree
CSeq: 1252 INVITE
Call-ID: rdw6Iy8zoIfKxg6LzJ7FSPdgBvIb8y
Allow: INVITE,ACK,BYE,CANCEL,REFER,NOTIFY,OPTIONS,PRACK
Expires: 120
Privacy: none
User-Agent: E71-2 RM-346 400.21.013
P-Preferred-Identity: sip:leifmadsen_cell@pbx.my_asterisk_server.com
Max-Forwards: 70
Content-Type: application/sdp
Accept: application/sdp
Content-Length: 447

v=0
o=Nokia-SIPUA 63437257072703500 63437257072703500 IN IP4 10.10.10.84
s=-
c=IN IP4 10.10.10.84
t=0 0
m=audio 49152 RTP/AVP 96 0 8 97 18 98 13
a=sendrecv
a=ptime:20
a=maxptime:200
a=fmtp:96 mode-change-neighbor=1
a=fmtp:18 annexb=no
a=fmtp:98 0-15
a=rtpmap:96 AMR/8000/1
a=rtpmap:0 PCMU/8000/1
a=rtpmap:8 PCMA/8000/1
a=rtpmap:97 iLBC/8000/1
a=rtpmap:18 G729/8000/1
a=rtpmap:98 telephone-event/8000/1
a=rtpmap:13 CN/8000/1

So beyond that, there shouldn’t be anything else you need to do. Using the same configuration in sip.conf for Asterisk should also work with Fring. Perhaps I’ll create another blog post in the future about using Fring with E71 if there is interest in that. Anyone who wants to try testing out some video calls through my Asterisk box using their Fring video enabled phone, just let me know offline and we’ll set something up!

Written by Leif Madsen

2010/03/19 at 11:28 am