Monthly Archives: August 2015

Lua Scripting – Replacing FQDN with IP in SIP Headers

A friend of mine at Cisco TAC pinged me a few days ago, asking to assist him with a case he’s working on that required a sip normalization script.

The call flow included a SIP Trunk to a conferencing system that was DNS-enabled.  CUCM was unable to lookup the DNS address (in this case due to a bug), and since the system was integrated directly to CUCM (not via CUBE), the only option for normalization was a Lua script.

The requirements of the script were:

  1. Find/Replace a number of potential FQDN/IP combinations
  2. Apply required normalization to “Contact” header
  3. Contact head must be modified for initial inbound INVITE, and all subsequent inbound responses to the INVITE
  4. Other messages should be ignored



Author : Jonathan Els
Email :
Version : 3.0


Find and replace FQDN with IP in Contact headers.
Script is applied to Inbound INVITEs and all Inbound INVITE responses

Future development:

None planned


M = {}


— Customer-specific DNS table initialization – edit on per-script basis
local dns = {}
dns[“”] = “”
dns[“”] = “”
dns[“”] = “”
local function process_contact_headers

— Get Contact header
local contact = msg:getHeader(“Contact”)
local iptest = “@(%d+%.%d+%.%d+%.%d+)”

— Check if exists and if URI host portion is FQDN
if contact and not contact:match(iptest) then
trace.format(” — Contact URI host portion matched FQDN”)
trace.format(” — Contact header is : %s”, contact)

— Iterate over domain and substitute if matched
for ip,fqdn in pairs(dns) do
if contact:match(fqdn) then
contact = contact:gsub(fqdn, ip)
trace.format(” — Matched on : %s”, fqdn)
trace.format(” — Modified to : %s”, ip)

— Modify contact header
msg:modifyHeader(“Contact”, contact)

— Apply to INVITE request and all INVITE responses
M.inbound_INVITE = process_contact_headers
M.inbound_ANY_INVITE = process_contact_headers
return M

Some Notes:

  • The requirement called for both request and response handling
    • M.inbound_INVITE
    • M.inbound_ANY_INVITE
  • The multiple handling requirement resulted in a “purposed-based” function being used to avoid duplication of code.
  • Some checks were added to skip and exit in the event that
    1. Contact header did not exist
    2. URI host portion was an IP Address.
  • Lua does not support full regex (regex is slow), so a standard IP approximation was used.  The “@” prefix in the match is used to ensure the match is on the URI.

Useful Resources:

The last resource from Cisco Live is possibly the best “How-To” out there!

Happy scripting.


Tagged , , , ,

Lua Scripting – Proxied Manager Breaks MWI for Centralized CUC Behind SME

I’ve been working as design and deployment lead on a globally significant full Collaboration on-premise deployment for the last 3 months (think 120 CUCM across 9 Leaf Clusters on 101 UCS C240’s) that’s been keeping me quite busy 🙂

As part of the deployment design phase, a decision was taken to centrally host Unity Connection for all 9 Leaf Clusters.  As I commenced with the dial plan design, while I reviewed the business requirements I identified a call flow that I knew would immediately create a problem.  Some like a board, pen and paper or even spreadsheets for call routing – I like to do these in my head as I jot down the configuration elements in notepad++.  Your preferred method is irrelevant – the point is always to model your call flow design prior to implementation – with the intention to find inherent call flow failures.

The client had a strong use case for a proxied manager configuration, with a secretary available to take calls on their behalf.  There are a number of ways to configure this, but from a routing perspective, a separate partition is always required for the manager, with reach-ability only from the secretary’s CSS.

The Challenge:

  • Call flow required is CUC > SME > Leaf > Manager Phone
  • MWI is routed from CUC via an Out-of-Dialog SIP NOTIFY
  • In the CUCM SIP construct, this uses the same Inbound CSS as a standard call

The Likely Result:

  • The manager’s MWI will never light up – no reach-ability in the inbound CSS without violating an inter-cluster proxied routing requirement
  • Depending on your configuration, the proxied line on the secretary’s phone is probably going to light up instead!

The requirement is not unique, but the advent of SIP, and wanting a scale-able solution posed a challenge.

Due to the scale of deployment and tight timelines, our local SE was kind enough to arrange some time with a BU dial plan specialist to review my dial plan design, with some recommendations along the way (what an awesome experience!).  I was keen to pose my dial plan issue to the BU, as I was quite sure that a special method would be needed to accommodate this.

After some discussion, a Lua script was proposed.  I was quite keen on the idea, as I’ve had some experience writing these before.  The call flow idea was actually quite simple:

  1. CUC > SME > Leaf (end-to-end SIP)
  2. SIP Normalization Script (on Leaf Trunk) > Custom Routing Prefix on Manager DN (think “**”)
  3. Translation Pattern (PreDot strip with correct re-prefixing) > Custom CSS with prioritization of Manager Partition(s)

The BU provided me a script for a similar case, which I customized to support my requirement:


Author : Jonathan Els


Script for separate handling of MWI to accommodate proxied partitions for centralized voicemail designs with SME – e.g. with Proxied Manager/Secretary configurations
Script strips initial chars (“0” hard-coded in this script) to add a prefix for custom routing

Future development:

1. Add contextual checks to specifically limit to MWI – possible matching on Content (“Messages-Waiting” etc.) or CUC source address could apply
1. Use prefix as script param.



function M.inbound_NOTIFY(msg)

— Set prefix for MWI
prefix = “**”

— Need to convert E.164 to **-prefixed string in request URI and To header
local m,r,v = msg:getRequestLine()
r=string.gsub (r,”sip:0(%d*)@”, “sip:” .. prefix .. “%1@”)
msg:setRequestUri (r )

local t = msg:getHeader(“To”)
t=string.gsub (t,”sip:0(%d*)@”, “sip:” .. prefix .. “%1@”)
msg:modifyHeader (“To”, t)

return M

In our dial plan, we deviated from the +-E.164 CVD best practice due to a limitation on the client’s billing system.  We preferred localized DID’s instead.  As a result, the above script uses the following pattern match:


Without excessive deviation, if your call routing requirement dictates the need for Lua scripting, please take the time to understand Lua Pattern Matching.  Lua’s about *speed*.  Regex is damn slow.

During testing, I hit a snag and reached out to the BU once again…

Looking at SDL showed the script to be working:

00240075.000 |17:09:45.622 |SdlSig   |SIPNormalizeReq                        |wait                           |SIPNormalization(2,100,78,1)     |SIPHandler(2,100,79,1)           |2,100,14,91.8^^*           |*TraceFlagOverrode

00240075.001 |17:09:45.622 |AppInfo  |//SIP/SIPNormalization/trace_sip_message: After inbound SIP Normalization msg is:


NOTIFY sip:**111001001@ SIP/2.0

Date: Wed, 24 Jun 2015 15:09:45 GMT

From: <sip:voicemail@>;tag=36349161

Event: message-summary

Content-Length: 23

User-Agent: Cisco-CUCM10.5

To: <sip:**111001001@>

Contact: <sip:voicemail@;transport=tcp>

Content-Type: application/simple-message-summary

Call-ID: ad6c800-58a1c839-13de1-c74a8c0@

Subscription-State: active

Via: SIP/2.0/TCP;branch=z9hG4bK13ecf35a0eda8

CSeq: 102 NOTIFY

Max-Forwards: 70


Messages-Waiting: yes

However, I soon found that the standard digit analysis engine was not being applied.  The TP’s in my CSS’s were not being matched!  I actually confirmed this by configuring my expected pattern – **111001001 – on an entirely different phone and watched its MWI light up.

The BU suggested that I try setting the Advanced CallManager Service Parameter Multiple Tenant MWI Mode to “True”.  In our initial discussions, I’d been informed that this was not required in the SIP Trunking use case, but this ultimately did not prove to be the case.  After doing this, the translation pattern kicked in and that elusive MWI lit up immediately.

Tagged , , , , , ,

Forcing MTP Killed the Mid-Call

There’s a common misconception with Cisco SIP trunking that the desperate “Forced MTP” will always solve no audio, one-way audio, DTMF inter-working and every other media negotiation failure under the sun. This is unfortunately not always the case.


On a deployment completed quite a while back, we faced a no-audio media issue in 9.1.x (determined to be due to CSCup07303) where I initially raised the white flag due to time constraints and forced the MTP on the SIP Trunk.  The issue arose due to a UCCX re-direct for an after-hours call flow.  Not the topic for discussion here, but just some background information (more on this later).

Fast forward 5 months, and 3 remote sites were deployed for the same system, following a CBO SIP Trunking solution via the Campus site.  After deploying the 3rd site, the client complained that inbound calls were failing and I was asked to investigate.

I reviewed the call flow to find a classic INVITE/UPDATE/Re-INVITE scenario, with CUCM ending the call with a BYE due to a frustrated end user hanging up (Reason: Q.850;cause=16).

The call flow was as follows:

  1. Inbound INVITE (EO)/200 OK/ACK from Service Provider
  2. Re-INVITE(EO – a=inactive)/200 OK/ACK from CUCM>CUBE>SP
    1. i.e Audio Termination
    1. A classic CUCM Delayed Offer MOH media negotiation attempt

Unfortunately at this point the call had already failed, with many SIP messages still to follow (for another day) before the final BYE.

So, what is actually going on here?!?  Let’s look at the SIP Ladder:


The offending message is:

May 27 08:57:04.713: //1396205/8DF8940DA2FF/SIP/Msg/ccsipDisplayMsg:
SIP/2.0 200 OK
Via: SIP/2.0/UDP;branch=z9hG4bK5C8CBBB5
From: <sip:12341234567@>;tag=815B2478-2382
To: <sip:22334455667@>;tag=SDjuthc01-nz5qnrc7wqej3qxa.o
Call-ID: SDjuthc01-780d708b807543c356c407ad79c35b25-a848bn0
CSeq: 101 INVITE
Timestamp: 1432717024
Contact: Anonymous <sip:2345234523@;transport=udp>
Server: Sippy
Portasip-3264-action: answer 2
Content-Length: 245
Content-Type: application/sdp

o=Sippy 2031015826430718550 1 IN IP4
t=0 0
m=audio 62848 RTP/AVP 18 96
c=IN IP4
a=rtpmap:18 G729/8000
a=fmtp:18 annexb=no
a=rtpmap:96 telephone-event/8000

Root cause?

An RFC non-compliant upstream softswitch, sending a=inactive instead of a delayed media offer – in this case not conforming to 14.2 of RFC 3261.

A UAS providing an offer in a 2xx (because the INVITE did not contain an offer) SHOULD construct the offer as if the UAS were making a brand new call, subject to the constraints of sending an offer that updates an existing session, as described in [13] in the case of SDP. Specifically, this means that it SHOULD include as many media formats and media types that the UA is willing to support. The UAS MUST ensure that the session description overlaps with its previous session description in media formats, transports, or other parameters that require support from the peer. This is to avoid the need for the peer to reject the session description. If, however, it is unacceptable to the UAC, the UAC SHOULD generate an answer with a valid session description, and then send a BYE to terminate the session.

I raised a case with the service provider, who simply couldn’t resolve the problem, as the offending device was actually on an upstream inter-connect with another provider.  Chaos ensued explaining this to the client.

Luckily, Cisco has some methods to support this non-compliance – introduce Send sendrecv in Mid-Call INVITE

When Send “sendrecv” in mid call INVITE is enabled, this feature inserts an MTP into the media path between the calling and calling devices, allowing the media connection to be disconnected between the Unified CM device and the MTP, while establishing and maintaining media between the MTP and the held device with a=sendrecv. On call resumption, the MTP is removed from the media path.

Unfortunately, this fix meant I also had to downgrade MOH support to use G729 as well:

This feature addresses the mid-call Delayed Offer INVITE issue for audio direction, but it cannot resolve the issue of a device responding with its last used codec rather than the full list of all supported codecs. This issue can be problematic in cases where a codec change is required on re-establishment of media, such as placing a G.729 call on hold and connecting it to a music on hold source where G711 is preferred.

So.. why am I blaming the forced MTP?

Well, when it’s forced into the call to begin with, yes… it will result in early offer, but its always in the call, and media is therefore always set up and terminated with every mid-call Re-INVITE – via a=inactive SDP.  The end result is that setting Send “sendrecv” in mid call INVITE on the SIP Profile had absolutely no effect – I had to disable MTP on the trunk, set Early Offer from the SIP Profile adn finally set the sendrecv param on the SIP Profile as well.


Tagged , , , , ,

DTMF Interworking and the MTP

I came across this a while back when deep diving MTP when preparing for the lab.  I’ve pretty much got it down now, but I keep coming back to it as a reference point.

I really struggled a lot with this at the CCNP level.  Not sure about MTPs conceptually?  Look no further!

Tagged , , , ,

Quick and Dirty DNS Testing

Quick and easy sanity checks…

My requirement was to test 500 A/PTR records.  The client didn’t feel comfortable with bulk loading the records, so the work had been split up to be manually added between multiple resources – I was concerned, and didn’t have much time to find the errors.

Process followed:

  1. Save a file containing all your IP’s
  2. Save a file containing all FQDNs
  3. Run the following from windows cmd:

FOR /F %i in (txt) DO nslookup %i >> resolutions-ip.txt 2>> failures-ip.txt

FOR /F %i in (.txt) DO nslookup %i >> resolutions-fqdn.txt 2>> failures-fqdn.txt

  1. Go have coffee and think how clever you are
  2. Realize that this could actually be scripted properly in Python and realize how clever you aren’t

This quickly gave me a great list of missed records from STDERR.  The duplicates and mismatched records were confirmed with some regex magic in notepad++ on the STDOUT output.

3mins work for pretty good yield, but if it’s a repetitive task (it wasn’t for me… yet…), script it properly!

Tagged , , ,

UCCX – CTI Registration Fails after CUCM Upgrade to 10.5(2) – CSCuq26061

Had a strange one today…

A colleague completed a CUCM upgrade from 10.5 in-version.  No issues were experienced after the minor upgrade.  However, a few days later the client called reporting their contact center and switchboard as down.  This had apparently occurred directly after a power failure in their server room.  Single server BE6K installation.

I jumped onto the gateway, confirming a 404 sent from CUCM to the SIP Gateway.  No routing changes had taken place, so i assumed something was down – immediately thinking CTI.  Their switchboard IVR was fairly complex, so a script had been written on UCCX instead of using Unity Connection AA functionality with Call Handlers.  Reviewing the CTI Ports and Route Points showed me the problem – both “Unknown” – i.e. down since the last reboot.

I next moved to UCCX, and first check CCX Serviceability, noting that Cisco Unified CCX Engine was in Partial Service.  Drilling down to the Sub-System, I could see that Unified CM Telephony Subsystem was marked as OUT OF SERVICE, which made perfect sense due to the non-registration on CUCM.  As all other services were in service, this ruled out any script-related issue as well.  So… time to look at  JTAPI.

After enabling Debugging on the JTAPI logs on CCX, the fault was clear from the logs:

226: Aug 07 13:07:03.201 SAST %JTAPI-JTAPI-7-UNK:[CTIRP_12345]CiscoRegistrationExceptionImpl caught: Device registration failed because of unsupported device IP Addressing capability
227: Aug 07 13:07:08.202 SAST %JTAPI-JTAPI-7-UNK:(P1-JTAPI_1)[MIVR_SS_TEL_PROVIDER-39-0-INIT][CTIRP_12345] getIPAddressingMode= 2
228: Aug 07 13:07:08.202 SAST %JTAPI-JTAPI-7-UNK:(P1-JTAPI_1)[MIVR_SS_TEL_PROVIDER-39-0-INIT][CTIRP_12345]Request: register( myhostname/, 0, capabilities: “G.711 A-law 64k 30 frame packet size”, “G.711 U-law 64k 30 frame packet size”, algorithmIDs: null, IPv6 address: null)

A quick google (which should have happened sooner!) identified the support forum thread, with an immediate bug match:

My only concern was only that I didn’t have an exact version match, as my UCCX was only on version 10.5.1, not 10.6 as quoted in the bug.  However, CUCM did have a similar match.

Workaround was easy – I implemented the CDC as per the documented workaround in CSCuq26061.  In my case, I had to apply this to both the CTI Ports and Route Points.  After a Device Reset, Data Resync, JTAPI Resync (both unnecessary really) and CCX Engine restart, the ports all came up.  I’d recommend BAT here if you face the same.  I tested this on one CTI Port, found it working, then applied to all + CTI RP’s.

Been hitting a few bugs in 10.5 for CCX – hope this helps someone else.


Tagged , , , , , , ,
Collaboration Engineer

All things Technology - Posts to save for when you need them

Gerry Keleghan's Blog

A Blog about Cisco Unified Communications


my personal journey to ccie collaboration

Striving for greatness

Thoughts on DevOps, emerging tech, and open source

Network Experts Blog

“Knowledge comes by eyes always open and working hands.”

SIP Adventures

A unified communications blog by Andrew Prokop

The Cloverhound Blog

Cloverhound Employees Talk Unified Communications and Contact Center


Fog navigator. Get out of the clouds. Down to earth solutions. @Warcop

Cisco Collab Engineering Tips

Michael White - CCIE #26626


Photography by Manos,


Thoughts and experiences of a Cisco Collaboration engineer after clearing the CCIE lab...

The Daily Post

The Art and Craft of Blogging

The Blog

The latest news on and the WordPress community.