Asterisk Exploitation: UUID extensions and the realtime dialplan switch

This article focuses on how I was able to use UUID’s generated within my voice application (a dialer) to place and track the progress of outbound calls against a realtime extension context that is also tracked and dynamically generated by way of res_curl and some simple Python based API services.

Realtime? I don’t mean realtime prioritization or realtime as a project codename. Asterisk supports realtime/dynamic configuration of many modules by way of extconfig.conf. This can be especially useful if you want to have a database driven set of SIP peers, voicemail boxes, or in my case a webhook helping define how the dialplan works using a realtime dialplan switch => ….

See: https://www.voip-info.org/asterisk-realtime-extensions/

My application stores dialer related data in a database and is responsible for tracking call progress. In the past I had created AMI and ARI related tools for this and this go around I had decided to apply the KISS principle while planning the servers and workers that will ultimately make up the skin and bones of this project.

Part of keeping things extra simple (and extra easy to diagnose later on) was to create scalable APIs that are easy to log and produce tracebacks from rather than dissecting asynchronous code. The added bonus was being able to restart parts of the project without restarting all services (monoserver) and easily rate-limit/buffer API calls using off-the-shelf tools.

Call requests in my project are identified by a UUID handed to me by an external request from a client. I wanted a simple way to utilize that UUID to track both the outgoing call as well as the internal extension it will ultimately connect to and was a bit disappointed to find out that realtime switching using res_curl didn’t put channel variables in the request headers or even make them simple to append to the URL when using a dialplan switch.

/etc/asterisk/extensions.conf...
[some-context-for-outbound]
switch => Realtime/default@my-webhook-outbound
[some-context-for-app]
switch => Realtime/default@my-webhook-app
...
/etc/asterisk/extconfig.conf...
my-webhook-outbound = curl,http://localhost:8080/webhook/outbound
my-webhook-app = curl,http://localhost:8080/webhook/app
...

Any call that ends up in some-context-for-outbound will ultimately be sent to http://localhost:8080/webhook/outbound and it will look a little something like this.

POST /webhook/outbound HTTP/1.1
Host: localhost:8080
User-Agent: asterisk-libcurl-agent/1.0
Accept: */*
Content-Type: application/x-www-form-urlencoded
exten=15558675309&priority=1&context=default

And an appropriate response, given that we don’t want any calls for that number, would be something like this:

HTTP/1.1 200 OK
Content-Type: application/x-www-form-urlencoded
exten=15558675309&priority=1&context=default&app=Hangup

Optionally you can use appdata to pass a string of all application arguments to the Hangup app (which accepts no arguments) or possibly say… Dial.

Bummer about this solution so far is that I have no way of knowing if the call I am originating using this technique is linked to the UUID I have in my database. If only I could….

Wait…

Could it be that simple?

Why yes… yes it can…

POST /webhook/outbound HTTP/1.1
Host: localhost:8080
User-Agent: asterisk-libcurl-agent/1.0
Accept: */*
Content-Type: application/x-www-form-urlencoded
exten=a21fb62c-bb9f-4929-82f6-c74ca7a58404&priority=1&context=default

Boom. Turns out I can just originate to Local/a21fb62c-bb9f-4929–82f6-c74ca7a58404@some-context-for-outbound and be on my merry way. When I originate the call I can send the answered call to a21fb62c-bb9f-4929–82f6-c74ca7a58404@some-context-for-app as well and now my webhook has to do all the work of defining the dialplan for each priority as the call progresses.

I sure wish I could also know what the UniqueID and LinkedID are for these calls however. For if I want to look at CDR/CEL data later.

That context variable sure is boring looking.

What… what is eswitch? Let me just plug that in.

/etc/asterisk/extensions.conf...
[some-context-for-outbound]
eswitch => Realtime//${CHANNEL(UNIQUEID)}-${CHANNEL(LINKEDID)}@my-webhook-outbound
[some-context-for-app]
eswitch => Realtime//${CHANNEL(UNIQUEID)}-${CHANNEL(LINKEDID)}@my-webhook-app
...

Oh yeah. That’s the ticket right there.

POST /webhook/outbound HTTP/1.1
Host: localhost:8080
User-Agent: asterisk-libcurl-agent/1.0
Accept: */*
Content-Type: application/x-www-form-urlencoded
exten=a21fb62c-bb9f-4929-82f6-c74ca7a58404&priority=1&context=1588546092.276-1588546092.275

At this point it’s time to just move on and finish up the application side of things! On the outbound webhook side I can set up CallerID variables, initiate MixMonitor if I want, and then use Dial with all the bells and whistles for options I want. Time to let Asterisk do what it’s good at. Asterisk things.

On the application webhook side of things I can better track the progress of the call, make dynamic decisions, and formulate a call status that can ultimately be used to determine business logic later on.

Off to go code some more… Farewell reader.

Photographer, writer, tech developer and outdoor enthusiast living in Eagle River, Alaska.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store