How to get the DID of a SIP trunk when the provider doesn't send it (and why some incoming SIP calls fail)

from: http://www.aussievoip.com.au/wiki/How+to+get+the+DID+of+a+SIP+trunk

The symptom: On a SIP trunk, you can't get an inbound route to work -
it just doesn't seem to recognize the number. You can get the call to
go to your any DID/any CID route, or maybe the call doesn't get answered at all. When you type sip debug
from the CLI, you can see (when you scroll back to the point where the
call came in) that a sip INVITE packet arrived, and it contained the
DID number in the sip To: header (in the form To: <sip:NUMBER@IP ADDRESS>), but you also see that the FROM_DID was set to s. In other words, you see a line that looks like this:

-- Executing Set("SIP/9995552368-09876543", "FROM_DID=s") in new stack

So there the DID number is, in the sip INVITE packet's To: header, but the CLI reveals that Asterisk isn't picking it up, and therefore it goes to your default inbound route.

(Oh, and for anyone who's still trying to figure out how to turn off sip debugging, the CLI command is sip no debug)

Fortunately this isn't a hard thing to work around, as long as the DID number really is in the sip To: header. First, create a context in extensions_custom.conf that looks like this:

[custom-get-did-from-sip]
exten => _.,1,Noop(Fixing DID using information from SIP TO header)
exten => _.,n,Set(pseudodid=${SIP_HEADER(To)})
exten => _.,n,Set(pseudodid=${CUT(pseudodid,@,1)})
exten => _.,n,Set(pseudodid=${CUT(pseudodid,:,2)})
exten => _.,n,Goto(from-trunk,${pseudodid},1)

Or,
thanks to naftali5, you can cut the above down to one line of code that
does the same thing, but is a bit less obvious to the casual reader:

[custom-get-did-from-sip]
exten => _.,1,Goto(from-trunk,${CUT(CUT(SIP_HEADER(To),@,1),:,2)},1)

(And speaking of naftali5, if you are using his Dialplan Injections module,
and want to put the above line in the Destination section, then you
will need to use a slightly different syntax (changing the commas to
bar characters), so it looks like this:

* Custom App: from-trunk,${CUT(CUT(SIP_HEADER(To)|@|1)|:|2)},1

The part after Custom App: is what you paste into the text box. This ONLY applies to Dialplan Injection users)

Then, in the trunk associated with the provider, change the trunk context statement (which should read context=from-trunk) to:

context=custom-get-did-from-sip

(Or for Dialplan Injection users, just use

context=injection-n

but
replace n with the actual injection number, which will appear next to
the injection name in the right-hand column menu of injections.)

And note that with such providers, you may have to move that
context statement from the USER details to the PEER details section.
This is why calls from some SIP providers sometimes fail to come in at
all - they effectively never "see" the User context and details,
therefore they don't see the context statement there and have nowhere
to go. It's also why you sometimes see instructions for sip providers
that leave the User context and User details sections totally blank,
but include a context statement in the peer details - in most such
cases it's because the provider is treating the customer as an end user
(like someone using a softphone or a VoiP adapter) rather than as a
peer, and they aren't sending DID information.

The above instructions may also solve the problem where you have
two (or more) trunks from the same provider, but Asterisk always treats
it as if all calls are coming in on one of the two trunks, therefore
again not allowing you to set up separate inbound routes for each
trunk. As long as the provider sends the number in the sip To header, the above code should set the DID properly.

If the first part of the To: statement is something other than a
DID number (a user name, for example), then you may have to add a line
just before the final Goto statement. For example, let's say the
provider is sending To: <sip:Fred@IP ADDRESS>
and your DID number (or at least, the number you want to use to denote
your inbound route) is really 5551212. You'd then use code similar to
this:

[custom-get-did-from-sip]
exten => _.,1,Noop(Fixing DID using information from SIP TO header)
exten => _.,n,Set(pseudodid=${CUT(CUT(SIP_HEADER(To),@,1),:,2)})
exten => _.,n,Set(pseudodid=${IF($["${pseudodid}"="Fred"]?5551212:${pseudodid})})
exten => _.,n,Goto(from-trunk,${pseudodid},1)

Or,
as long as you only have ONE trunk from that provider, you could always
just cheat a little and hardcode the desired DID in a separate custom
context, like this:

[custom-stupid-provider]
exten => _.,1,Noop(Fixing DID to 5551212)
exten => _.,n,Goto(from-trunk,5551212,1)

And
use the name of this context in the trunk settings. I hear you asking,
why not just do it this way on all trunks with this issue? Well,
because if you add a second trunk from the same provider, this won't
work correctly for both trunks, and if you ever change your number and
then forget what you've done and just try to set your inbound route to
the new number, it won't work. And besides all that, if you have more
than one SIP provider that doesn't send proper DID, you'd have to
create a separate custom context for each of them, instead of having
one custom context that works for all of them.

One final note for Free World Dialup users, you may find that sip
calls will still not come in until you put the following statement in
sip.conf:

insecure=invite

I have no idea why that works, but it seems to make a difference.

What if the provider doesn't send the number in the sip To: header?

There is at least one provider that actually sends a s character instead of a number in the sip To:
header. What can you do with a provider like that? Well, all may not be
lost. If you only have a single trunk from that provider, you can just
use the "cheat" shown above, since it doesn't rely on the contents of
the sip headers. If, however, you have TWO or more trunks from the same
provider, you can do a sip debug from the CLI and watch as calls come in on each trunk and note whether there are any consistent differences.

For example, if you have two lines on the same account, the
provider will often assume that you are using a VoIP adapter (such as a
Sipura or Linksys) and will use port 5060 for line 1, and port 5061 for
line 2. That difference might show up in the headers of the sip INVITE
packet, for example:

Via: SIP/2.0/UDP 111.222.333.444:5060;branch=z9hQ4bK67sc0a8e;rport

In
this case, you see that there is a colon (:) before the port number and
a semicolon following, and that there are actually TWO colons on the
line before the port number, so maybe this would work:

[custom-really-stupid-provider]
exten => _.,1,Noop(Fixing DID using port from SIP VIA header)
exten => _.,n,Set(pseudodid=${CUT(CUT(SIP_HEADER(Via),;,1),:,3)})
exten => _.,n,Set(pseudodid=${IF($["${pseudodid}"="5060"]?5551111:${pseudodid})})
exten => _.,n,Set(pseudodid=${IF($["${pseudodid}"="5061"]?5552222:${pseudodid})})
exten => _.,n,Goto(from-trunk,${pseudodid},1)

Or,
if you only have two trunks from this provider, you probably could just
condense the two test lines into one, by testing for one port number
and assuming the other if the conditional test fails, like this:

exten => _.,n,Set(pseudodid=${IF($["${pseudodid}"="5060"]?5551111:5552222)})

Note that the code in this section is untested,
it's just to give you some ideas about how to possibly handle the
really oddball situation were you have two (or more) lines from the
same provider, and cannot find any other way to differentiate them.
And, don't automatically assume you have a bigger problem than you
actually have - for example, it may well be that having different port
numbers on the different trunks would allow Asterisk to distinguish
them enough that the simple "cheat" method would work (you'd have to
make one for each trunk, of course).