Microsoft Teams Direct Routing with Issabel (Asterisk)



  • Should have Issabel server properly installed with ip public and . The server firewall should be hardened by only allowing Carrier and Microsoft cloud ip address blocks ( Even better if the only maintenance can only be accessed by VPN. Dont open your Issabel webGUI, SSH, SIP & RTP ports to public internet whenever possible.
  • My Issbel (Asterisk) server is already connected to Ofon as the PSTN Carrier, and already has a DID assigned.
  • Requires to edit chan_sip.c to comply with Microsoft Teams Phone System that demands SIP From and Contact header host part to be FQDN. From header is easy, just add fromdomain at the Asterisk trunk config and you’re good. The Contact header is the tricky one, based on this screenshot clue (stolen from thread
  • By half-assed editing the chan_sip.c , I expect there will be repercussion somewhere else in the system (plus I am no good at C, should find a better way to insert the change with more elegant solution), so dont share the PBX with something else for production, and use this as POC only.
  • Dont ever think to commercialize this without Microsoft approval, nor use this for officials. You may not be able to open tickets if you encounter problems with this installation although you are a legit Office 365 tenant with Phone System license. The certified SBC list can be found here.
  • Should have access to DNS server to add TXT type record for domain authentication.
  • Should have global admin account to make changes in O365 portal.
  • In this example, I have two E1 O365 + Phone System licenses. One to be assigned to my account and one to be assigned to SIP trunk domain dummy user.
  • You cant do multi tenant with this installation. Asterisk itself is a single realm (CMIIW).
  • Still cant find how to modify Contact header in OPTIONS, hence you’ll find tlsdontverifyserver=yes in Issabel general config.
  • Will periodically update this post with something new whenever I find improvement. So forgive me if you find something different when you read back the post later.

Microsoft Teams Phone System Side Config

In this stage you will need to add an SSL’ed domain to Office 365 portal. Microsoft-recommended CA list can be found here. I myself use GeoTrust.

  • Microsoft has a very detailed documentation that can be found at . I wont rewrite the details here.
  • Using global admin to add domain (mine is, to O365 admin portal.
  • Add a dummy user for that domain and assign O365 + Phone System license for that dummy user. For example, my dummy user for the newly added domain is If successfully added, I will find the user in Active users table like this:
  • that is how Microsoft Teams will recognize the SIP trunk to our Issabel (Asterisk) server and assign license to the trunk.
  • Login using powershell to your account using global admin user. Again, the powershell preparation wont be repeated here since the detailed documentation can be found at Next steps will require us to import Sfbonline module to powershell.
  • Start the session (you will be asked for password on a popped up windows) :
$sfb = New-CsOnlineSession -Username ""
Import-PSSession $sfb -AllowClobber
  • Add the Issabel (Asterisk server) as PSTN Gateway:
New-CsOnlinePSTNGateway -Fqdn -SipSignalingPort 5061 -ForwardCallHistory $true -Enabled $true -ForwardPai $true -MaxConcurrentSessions 5
  • See if the server is properly added with Get-CsOnlinePstnGateway :

Identity                            :
InboundTeamsNumberTranslationRules  : {}
InboundPstnNumberTranslationRules   : {}
OutboundTeamsNumberTranslationRules : {}
OutboundPstnNumberTranslationRules  : {}
Fqdn                                :
SipSignalingPort                    : 5061
FailoverTimeSeconds                 : 10
ForwardCallHistory                  : True
ForwardPai                          : True
SendSipOptions                      : True
MaxConcurrentSessions               : 5
Enabled                             : True
MediaBypass                         : False
GatewaySiteId                       :
GatewaySiteLbrEnabled               : False
FailoverResponseCodes               : 408,503,504
GenerateRingingWhileLocatingUser    : True
PidfLoSupported                     : False
MediaRelayRoutingLocationOverride   :
ProxySbc                            :
BypassMode                          : None
  • Create a routing and routing policy that will utilize the Issabel (Asterisk) server:
Set-CsOnlinePstnUsage -Identity Global -Usage @{Add="Default"}

New-CsOnlineVoiceRoute -Identity "CatchAll" -NumberPattern ".*" -OnlinePstnGatewayList -Priority 1 -OnlinePstnUsages "Default"

New-CsOnlineVoiceRoutingPolicy -Identity "DefaultVoicePolicy" -OnlinePstnUsages "Default"
  • Assign DID & VoiceRoutingPolicy to my account.

Issabel (Asterisk) Side Config

We will have two SIP connection configs for Microsoft Teams Phone System and two SIP connection configs for Carrier. Each connection will have different contexts. One SIP connection for Microsoft Teams will be from-internal, so call from Microsoft Teams will be treated as call from extension. And the other SIP connection will be treated as outbound trunk with from-trunk context. Same deal with the two SIP connections toward Carrier.

Microsoft provides 3 hosts to connect a SIP trunk with:


This example will only test the first one (

  • Adding Trunk to Microsoft Teams from PBX -> PBX Configuration -> Trunks. Add SIP Trunk and fill these parameters :
Trunk Name: MSTeams-Outbound
PEER Details:
  • And as “extension” add the following configs to sip_custom.conf using PBX -> Tools -> Asterisk File Editor :
  • To refer to certifcate files, go to PBX -> PBX Configuration -> Unembedded IssabelPBX. At the following page, go to Settings -> Asterisk SIP Settings and then Add field at the Other SIP Settings with these:
  • Save and reload the config.
  • Add the Outbound Routes to Microsoft Teams and Carrier (Microsoft Teams outbound should be aboive the Carrier). Since my carrier mostly sends with prefix 0, I have to convert it to E.164. Please modify these according to your apporpriate settings:

At this point, you should be able to call outbound from Microsoft Teams account but not the other way (inbound). As mentioned before, Microsoft Teams Phone System require us to send From and Contact header host as FQDN. The trunk settings in Asterisk wont change Contact header host to FQDN hence we’ll receive this message:

Via: SIP/2.0/TLS;branch=z9hG4bK4e781f8a;rport
Max-Forwards: 70
From: "02139700001" <>;tag=as36acd9d9
To: <>
Contact: <;transport=tls>
CSeq: 102 INVITE
User-Agent: Asterisk 16.7.0
Date: Fri, 08 May 2020 04:45:38 GMT
Supported: replaces, timer
Content-Type: application/sdp
Content-Length: 1324

SIP/2.0 403 Forbidden
FROM: "02139700001"<>;tag=as36acd9d9
TO: <>
VIA: SIP/2.0/TLS;branch=z9hG4bK4e781f8a;rport
REASON: Q.850;cause=63;text="735a16a2-5f83-4cb0-bdec-9cb64edff551;Provided Trunk FQDN '' is not allowed. Connection allows following fqdns: *,, *"
SERVER: Microsoft.PSTNHub.SIPProxy v.2020.5.6.2 i.ASEA.2


There is no Asterisk source in Issabel distro so we have to get it ourself. From Issabel linux console, git clone the Asterisk github and checkout for 16.7.0 (since this is my Issabel’s Asterisk version).:

cd /usr/src
git clone
cd asterisk
git checkout 16.7.0

Edit file /usr/src/asterisk/channel/chan_sip.c. Look at build_contact() we will find these lines:

static void build_contact(struct sip_pvt *p, struct sip_request *req, int incoming)
        char tmp[SIPBUFSIZE];
        char *user = ast_uri_encode(p->exten, tmp, sizeof(tmp), ast_uri_sip_user);
        int use_sips;
        char *transport = ast_strdupa(sip_get_transport(p->socket.type));

        if (incoming) {
                use_sips = uas_sips_contact(req);
        } else {
                use_sips = uac_sips_contact(req);

        if (p->socket.type == AST_TRANSPORT_UDP) {
                ast_string_field_build(p, our_contact, "<%s:%s%s%s>", use_sips ? "sips" : "sip",
                        user, ast_strlen_zero(user) ? "" : "@",
        } else {
                ast_string_field_build(p, our_contact, "<%s:%s%s%s;transport=%s>",
                        use_sips ? "sips" : "sip", user, ast_strlen_zero(user) ? "" : "@",
                        ast_sockaddr_stringify_remote(&p->ourip), ast_str_to_lower(transport));

The last conditional lines are where the Contact header gets value from. Since we only need to modify for TCP transport, edit the line:

 else {
                ast_string_field_build(p, our_contact, "<%s:%s%s%s;transport=%s>",
                        use_sips ? "sips" : "sip", user, ast_strlen_zero(user) ? "" : "@",
                        ast_sockaddr_stringify_remote(&p->ourip), ast_str_to_lower(transport));

to become :

 else {
                ast_string_field_build(p, our_contact, "<%s:%s%s%s;transport=%s>",
                        use_sips ? "sips" : "sip", user, ast_strlen_zero(user) ? "" : "@",
                        p->fromdomain, ast_str_to_lower(transport));

p->fromdomain will follow whatever “fromdomain=” value in the SIP trunk config.

Got input from Igo Cunha that the call from MSteams to PSTN will be disconnected after 6 sec. I can confirm I got random disconnect call at about 6 sec from the same direction. Try replace:

with your Asterisk's FQDN string (e.g "" in my case) instead of p->fromdomain.

Thanks Igo!

I understand this is not elegant way, but that should do it. Compile the source and we will have brand new Backup the original one and replace it after:

copy /usr/lib64/asterisk/modules/ /usr/local/src/
copy /usr/src/asterisk/channels/ /usr/lib64/asterisk/modules/

then reload the module from Asterisk console:

asterisk -vr

ast*CLI> module reload
Module '' reloaded successfully.
 Reloading SIP

Now test call to inbound, we should have correct SIP Contact header requirement as follows:

Via: SIP/2.0/TLS;branch=z9hG4bK394b6483;rport
Max-Forwards: 70
From: "02139700001" <>;tag=as20858906
To: <>
Contact: <;transport=tls>
CSeq: 102 INVITE
User-Agent: Asterisk 16.7.0
Date: Fri, 08 May 2020 04:54:36 GMT
Supported: replaces, timer
Content-Type: application/sdp
Content-Length: 1324

and the call went through:


Although it is possible to connect Direct Routing with Asterisk, still easier using Kamailio (and OpenSIPS) since they’re built solely for SIP packet engineering. Until some of them become certified with Microsoft, I guess I will be using the already ceritfied ones, like Sonus or AudioCodes, or just connect to a hosted Direct Routing Provider in Indonesia, like Ofon. Alternatively, there are Kamailo based products start providing hosted DR, like Gilawa and dSIPRouter. Check them out.

Complete Configs


27 thoughts on “Microsoft Teams Direct Routing with Issabel (Asterisk)”

    1. Hi, sorry for late reply. It’s long holiday here. Email is . This implementation is not yet complete because I havent succeed with OPTIONS and REFER. It just works minimally. Are you sure to implement this?

  1. Hello first thanks for publishing the article and helping. I did all the step by step and I’m having a problem and maybe you can help. I can make calls to Issabel -> Teams and I have no problem. When I make calls from Teams -> Issabel the call goes down in 6 seconds. And that only happens with the compiled file

    With the original file without the modifications, I can call Teams -> Issabel and the call will not go down. Did you have the same problem can you help me?

    Cli-> message error:
    retransmission timeout reached on transmission and chan_sip.c:4143 retrans_pkt: hanging up call

    If possible, can you send me your compiled file so that I can test it and see if the same problem occurs? thank you very much and great day. Setup Issabel 4 -> Asterisk 16

    1. Hi,

      Is this behind NAT? If it is so, I haven’t tested it behind NAT. I just put ip public right there. Any email where I can send you my compiled ?

      1. Thanks for the reply and attention. Yes .. please send Yes, I’m after a NAT. What happens is that the original asterisk 16.4 file works normally called Teams -> Asterisk. When I make the change

        else {
        ast_string_field_build (p, our_contact, “”,
        use_sips? “sips”: “sip”, user, ast_strlen_zero (user)? “”: “@”,
        p-> fromdomain, ast_str_to_lower (transport));

        I start making calls from Asterisk to Teams normally and I can no longer make calls from Teams to Asterisk (Call drops with 6 seconds.) I tried to make the change you suggested without success … I am waiting to send the file to make the test. Thank you very much for your attention again.

        1. Update

          Thanks for the solution. I was compiling the term wrongly because it was not a variable. And yes the solution works. After changing p-> fromdomain to the fqdn of my PBX the call became stable. Thank you very much for your help and beautiful work. If you have new updates please share. Once again thank you very much for your attention.

          1. Awesome! Glad to know it works finally. I assume you wouldnt need my compiled, right?

      2. Hi godril, could you help me with the file, I don’t know what I’m doing wrong but when I proceed to compile it throws me an error

    2. Hi, I can confirm that the call will be randomly disconnect on 6 sec. What I mean is from 5 calls I can get 2 or 3 calls disconnect on 6 secs.

      Then I tried change p->fromdomain to “sub.domain.tld” (this is your asterik fqdn) instead, the call can survive longer. Can you please try that and share with me what the result?

  2. Pingback: Complete Issabel Configs for MSTeams Direct Routing – (v2.0)

  3. Jorge Atehortua

    Hi, I did all the information above. Can you help me why my trunk is unreachable? What could be? Thanks Jorge

  4. Hi godril, could you help me with the file, I don’t know what I’m doing wrong but when I proceed to compile it throws me an error

    1. Sorry for really late reply, been in a project so just got chance to check blog.

      How can I help? what error did you get?

      1. Pak godril, layanan ofon yang dipakai, layanan apa ya namanya(saya lihat websitenya ada banyak macam layanannya)? selama ini saya langganan sip trunk Telkom (hanya bisa on premises) saya mao yg bisa diakses secara cloud, oiya terimakasih atas tutorialnya yang sangat berguna, it works like magic

        1. Halo,

          Salah satunya SIP trunk juga, dan biasanya bisa bekerja sama dengan ISP yang dikehendaki pengguna. Layanan lainnya ada hosted PBX yang juga banyak dipakai untuk dapat diakses dari mana pun. Selain itu da juga Hosted MSTeams Direct Routing.

          Terima kasih juga sudah membaca blog saya. Senang bisa membantu.

  5. Alejandro Latini

    I’m having issues where the trunk to MS is unrechable. TLS seems to be ok according to cli. I can confirm i have firewall ports open for MS addresses.

    On the management console for 0365 says there’s no response from mi FQDN, no SIP response. Issabel VM is on a Public IP, no nat is being used, just some firewall rules. What am i missing??

    1. Hi,

      In my case, I already have a wildcard certificate from GeoTrust. To obtain the certificate you can generate the CSR from wherever machine you want. Doesnt matter if you generate the CSR from your laptop and plant the obtained certificates from MS recommended CA to your Issabel.
      The list of MS recommended CAs can be found here:

      Make sure you also download Baltimore root CA for mutual TLS (since MS is using Baltimore root certificate) that can be found here:

  6. Christopher Naranjo


    I’ve got outbound calls working fine but inbound (issable -> teams ) just like not response to the invite or timeout, firewall is Ok, I working with let’sencrypt

    1. Does the contact header in INVITE contain your hostname already? Usually when Teams doesnt respon to invite because the contact header doesnt contain the hostname that is registered as in OnlinePSTNGateway.

  7. Hi ,
    you did a perfect job with your Issabel!
    I’ve been doing the same now with native Asterisk 17.7 with chan_sip too, all is working!!

    Only a little detail is not working, can’t hear anything!
    But only when I do calls to or from Teams!

    The rest is working, all other clients doing directly via siptrunk of the provider and all is ok!
    Do you have an idea?
    Best regards.

  8. Hi ,
    you did a perfect job with your Issabel!
    I’ve been doing the same now with native Asterisk 17.7 with chan_sip too, all is working!!

    Only a little detail is not working, can’t hear anything, no voice! 🙂
    But only when I do calls to or from Teams!

    The rest is working, all other clients doing directly via siptrunk of the provider and all is ok!
    Do you have an idea?
    Best regards.

    1. Hi Josef,

      Is it possible for you to share the SIP dialogs when falling to/from Teams via Asterisk? Especially the INVITE and 200OK SIP headers? Maybe we can find the answer there.


  9. This is really awesome, but would be great if we had the same option for PJSIP. PJSIP has the option to define a static FQDN, but I can’t find a way to do this dynamically as mentioned here, by referencing an endpoint parameter (such as fromdomain, from_domain in pjsip.conf).

Leave a Comment

Your email address will not be published. Required fields are marked *