This week’s #FridayFun relates to something that came up this past week. Without sharing exact details, imagine the PBX system serves a facility where calls to and from some of the extensions are carefully controlled. The kind of place where one might choose to stay for a while and not influenced by the temptations of the outside world.
The same system also serves staff, which generally don’t have inbound and outbound call restrictions. As it’s very minimally secure, the inbound and outbound call restrictions are easily controlled using the existing features in inbound and outbound routes. The question arose, how to prevent one of the staff from placing an outbound call, and then transferring (even accidentally) the call to one of the secured extensions.
As this type of thing comes up only rarely (in my experience) I thought I would document how transfer dialplan works in fpbx. In Asterisk, when you setup a channel, you can define a channel variable, TRANSFER_CONTEXT and set it to an Asterisk context. If the device on that channel initiates a transfer, then the call is sent to the specified dial string in this context. FreePBX doesn’t define this variable individually for each channel, the transfer context is set in a global variable
root@tangopbx5:~# asterisk -x "dialplan show globals" | grep TRANSFER_CONTEXT
TRANSFER_CONTEXT=from-internal-xfer
The context from-internal-xfer
is essentially identical to from-internal
so the transferred call proceeds pretty much like a normal local call. But we can interrupt this with our own dialplan as long as we step lightly.
Locate the file /etc/asterisk/globals_custom.conf
and add this line to override the default value for the transfer context:
TRANSFER_CONTEXT=from-internal-xfer-debug
Then create that context and add a few lines before sending the call to the normal transfer context, somthing like this in /etc/asterisk/extensions_custom.conf
[from-internal-xfer-debug]
exten => _.,1,Noop(entering user defined context from-internal-xfer-debug in extensions_custom.conf)
exten => _.,n,DumpChan
exten => _.,n,Goto(from-internal-xfer,${EXTEN},1)
Reload the dialplan and now when 7652 initiates a blind transfer to send 7653 to 7654, I see these log entries:
-- Executing [7654@from-internal-xfer-debug:1] NoOp("PJSIP/7653-00000050", "entering user defined context from-internal-xfer-debug in extensions_custom.conf") in new stack
-- Executing [7654@from-internal-xfer-debug:2] DumpChan("PJSIP/7653-00000050", "") in new stack
Dumping Info For Channel: PJSIP/7653-00000050:
================================================================================
Info:
Name= PJSIP/7653-00000050
Type= PJSIP
Variables:
SIPREFERTOHDR=sip:7654@redacted.me:5160
SIPREFERREDBYHDR="7652"<sip:7652@redacted.me:5160>
================================================================================
-- Executing [7654@from-internal-xfer-debug:3] Goto("PJSIP/7653-00000050", "from-internal-xfer,7654,1") in new stack
-- Goto (from-internal-xfer,7654,1)
(many lines removed for clarity)
The debug output shows a few variables that we can parse to get the relevant parties to the transfer. Armed with this info and a bit of string manipulation, we can update our custom context to this:
[from-internal-xfer-debug]
exten => _.,1,Noop(entering user defined context from-internal-xfer-debug in extensions_custom.conf)
; exten => _.,n,DumpChan
exten => _.,n,Noop(Extension being transferred: ${AMPUSER})
exten => _.,n,Noop(Extension doing the transferring: ${PJSIP_PARSE_URI(${SIPREFERREDBYHDR},user)})
exten => _.,n,Noop(Extension receiving the transfer: ${PJSIP_PARSE_URI(${SIPREFERTOHDR},user)})
exten => _.,n,Goto(from-internal-xfer,${EXTEN},1)
After reload, now when we initiate a blind transfer, I see the following log lines:
-- Executing [7654@from-internal-xfer-debug:1] NoOp("PJSIP/7653-0000005b", "entering user defined context from-internal-xfer-debug in extensions_custom.conf") in new stack
-- Executing [7654@from-internal-xfer-debug:2] NoOp("PJSIP/7653-0000005b", "Extension being transferred: 7653") in new stack
-- Executing [7654@from-internal-xfer-debug:3] NoOp("PJSIP/7653-0000005b", "Extension doing the transferring: 7652") in new stack
-- Executing [7654@from-internal-xfer-debug:4] NoOp("PJSIP/7653-0000005b", "Extension receiving the transfer: 7654") in new stack
-- Executing [7654@from-internal-xfer-debug:5] Goto("PJSIP/7653-0000005b", "from-internal-xfer,7654,1") in new stack
-- Goto (from-internal-xfer,7654,1)
That’s the basic framework, a means of safely injecting your own dialplan in the sequence of a blind transfer, and a means of identifying all of the parties to a transfer. This works when using a blind transfer feature on phone, and with the DTMF feature code in Asterisk.
None of this, however, will work for attended transfers. At this point, I’m not sure how or if one can identify the beginning of a blind transfer, as from an Asterisk dialplan point of view, they appear identical to a normal call. If anyone has any tips in this regard, I would love for you to share them. If I get a starting point, I will update this thread.
That’s it for this week, have a great weekend all!