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:
- Find/Replace a number of potential FQDN/IP combinations
- Apply required normalization to “Contact” header
- Contact head must be modified for initial inbound INVITE, and all subsequent inbound responses to the INVITE
- Other messages should be ignored
Script:
–[[
Author : Jonathan Els
Email : jonathanelscpt@gmail.com
Version : 3.0Description:
Find and replace FQDN with IP in Contact headers.
Script is applied to Inbound INVITEs and all Inbound INVITE responsesFuture development:
None planned
–]]
M = {}
trace.enable()
— Customer-specific DNS table initialization – edit on per-script basis
local dns = {}
dns[“1.1.1.1”] = “hostname1%.rootdomain%.com”
dns[“2.2.2.2”] = “hostname2%.rootdomain%.com”
dns[“3.3.3.3”] = “hostname3%.subdomain%.rootdomain%.com”
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)
break
end
end
end
end— 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
- Contact header did not exist
- 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:
- http://www.cisco.com/c/en/us/td/docs/voice_ip_comm/cucm/sip_tn/9_1_1/sip_t_n.html
- https://supportforums.cisco.com/video/12151771/guide-sip-normalization-cucm-and-lua-scripting
- https://www.ciscolive.com/online/connect/sessionDetail.ww?SESSION_ID=81835&tclass=popup
The last resource from Cisco Live is possibly the best “How-To” out there!
Happy scripting.
#dontcalltac