ayonik GmbH
    • Home
    • Projektmanagement
      • Überblick
      • Interim Projektmanager
      • Projekt Quick-Check
      • Projekt Audit
      • Projektsanierung
      • Risikomanagement
      • Download PM-Vorlagen
      • Projektabläufe optimieren
      • Unser Ansatz
    • Über uns
    • Blog
    05. November 2019

    Proof of Concept: Connecting Microsoft Teams via Direct Routing with an Asterisk PBX

    05. November 2019
    Share:

    In a proof-of-concept, ayonik experts have connected the open source PBX Asterisk to Microsoft Teams via Direct Routing. Inbound- and Outbound calls from and to the PSDN can be routed this way. Here we explain, how it works - and why you shouldn't use this in a productive environment. 


    Update 30.04.2021: The PowerShell module "SkypeOnlineConnector" is not supported anymore. Blog post updated to reflect new "MicrosoftTeams" module.

    REMARK: All shown configurations are just a proof of concept, which we publish for testing and education purposes. The solutions is NOT certified by Microsoft and does NOT consider all necessary security measures. This is NOT planned to be used in a productive environment. Normally for example an SBC will be used between the PBX and MS Teams, which isn't here. Ignoring this warning might lead to hakers intrude your sytem and start expensive calls on your bill! All information below is provided on an as-is basis without any warranty. ayonik is not liable for any damages, that will arise by using this information.

    All given information below is as of November, 2019.

    Short conclusion:

    1. We got Asterisk to work with Microsoft Direct Routing, BUT
      • Asterisk doesn't work with Microsoft Teams without a (small but dirty) code change. Reason is, that Asterisk/pjsip resloves FQDN's in the SIP Header to IP's by default, which cannot be changed by configuration. But Microsoft Teams needs the FQDN.
      • Microsoft does not list Asterisk as a supported PBX. So, even when it works, it's dangerous. Microsoft or Asterisk/pjsip might introduce changes, which can stop this solution from working
    2. So this solution should not be used in a productive environment, where one relies on the functionality.

     

    If you have any suggestions or questions about this article, just contact us on asterisk (at) ayonik.de.

     

    Prerequisites

    • You should be familiar with Asterisk installation and configuration with pjsip, as well as with Office 365 configuration
    • Installed Asterisk System
    • One of the following licences:
      • Office 365 Enterprise E3 (including SfB Plan2, Exchange Plan2, and Teams) + Phone System
      • Office 365 Enterprise E5 (including SfB Plan2, Exchange Plan2, Teams, and Phone System)
    • Remark: A calling plan is not needed, as we route outgoing Teams calls via our Asterisk PBX.
    • The PowerShell-Extension "SkypeOnlineConnector" (download here). This in turn needs PowerShell 5.0, plus a special version of Visual C++ 2017 Runtime.
    • The PowerShell-Extension "MicrosoftTeams" (installation instructions here). This in turn needs PowerShell 5.1.
    • Certificate for a Domain, which points to the external IP address of Asterisk (might be a wildcard certificate)
      Please consider, that
      1. *.domain.tld only allows e.g. sipconnect.domain.tld, but not sipconnect.test.domain.tld!
      2. The certificate has to be issued by one of the root CA's, which are trusted by Microsoft. See here for details:
        https://docs.microsoft.com/en-us/microsoftteams/direct-routing-plan#public-trusted-certificate-for-the-sb

    Currently Asterisk does not fulfil the requirement, that SIP options packets must contain the FQDN of your Asterisk machine in the "CONTACT" header. Instead of that, Asterisk resolves the FQDN to an IP address, which does not work with Microsoft Teams.

    Therefore a small code change is necessary, which then has to be compiled and installed.

    ATTENTION: This change hardcodes the FQDN into the CONTACT and VIA header and cannot be re-configured in any way. This is only a workaround, until Asterisk/pjsip possibly allows FQDN's in CONTACT header via configuration)

    The change is to be made in the res_pjsip_nat.c (which resides in our debian test system here: /usr/src/asterisk-16.5.1/res):

    In function static pj_status_t nat_on_tx_message(pjsip_tx_data *tdata)

    replace this line pj_strdup2(tdata->pool, &uri->host, ast_sockaddr_stringify_host(&transport_state->external_signaling_address));

    with this line pj_strdup2(tdata->pool, &uri->host, "<your asterisk FQDN>");

    and this line pj_strdup2(tdata->pool, &via->sent_by.host, ast_sockaddr_stringify_host(&transport_state->external_signaling_address));
    with this line pj_strdup2(tdata->pool, &via->sent_by.host, "<your asterisk FQDN>");

    (This hint was found here: https://asterisk-dev.digium.narkive.com/ucZYhaLE/asterisk-16-pjsip-invite-contact-field-and-fqdn#post12)

    After this change, the Asterisk system has to be compiled and installed. Information on compiling and installing Asterisk is available in various internet resources and therefore is not covered here.

    Configuration of Microsoft Teams

    Register your Domain in Office 365

    If not done already, open your Office 365 Admin Center (https://admin.microsoft.com) and go to the domain management page. From there, add your domain and follow the instructions. Please consider, that you have to have access to your domain management tool at your registrar.

    If your Asterisk is e.g. on sipconnect.domain.tld, you have to add "domain.tld" in Office 365 custom domain configuration (not the server sipconnect.domain.tld).

    Next, the Asterisk SIP Trunk has to be made known to MS Teams. To do so, a Windows Power Shell has to be connected to Microsoft Teams.

    Connect PowerShell to Microsoft Teams
    1. Execute a Windows PowerShell as Administrator
    2. Execute these commands:

      Import-Module SkypeOnlineConnector
      $userCredential = Get-Credential This command asks for Office 365 Administrator credentials. Please enter the Office 365 Administrator credentials.
      $sfbSession = New-CsOnlineSession -Credential $userCredential

      Import-PSSession $sfbSession
      Install-Module MicrosoftTeams
      Import-Module MicrosoftTeams
      $credential = Get-Credential This command asks for Office 365 Administrator credentials. Please enter the Office 365 Administrator credentials.
      Connect-MicrosoftTeams -Credential $credential
      Remark: When you get an error message in line 3, then probably the "Windows Remoteverwaltung" service is not running. Execute "services.msc" via "Windows-R" key combination and start "Windows Remoteverwaltung" service. Alternatively, the Basic Authentication has to be switched on (set Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\WinRM\Client\AllowBasic = 0x00000001 with Registry Editor). But be really sure, what you do, before doing this.

    3. With Get-Command *onlinePSTNGateway* you should get:

      CommandType Name                        Version Source
      -
      Function    Get-CsOnlinePSTNGateway     1.0     tmp_xq5wu12r.dxr
      Function    New-CsOnlinePSTNGateway     1.0     tmp_xq5wu12r.dxr
      Function    Remove-CsOnlinePSTNGateway  1.0     tmp_xq5wu12r.dxr
      Function    Set-CsOnlinePSTNGateway    1.0      tmp_xq5wu12r.dxr

      CommandType Name                       Version Source
      ----------- ----                       ------- ------
      Function    Get-CsOnlinePSTNGateway    2.3.0   MicrosoftTeams
      Function    New-CsOnlinePSTNGateway    2.3.0   MicrosoftTeams
      Function    Remove-CsOnlinePSTNGateway 2.3.0   MicrosoftTeams
      Function    Set-CsOnlinePSTNGateway    2.3.0   MicrosoftTeams

    4. This shows, that the Connection was successful and the commands are available, now.

    Make your Asterisk SIP Trunk known to Microsoft Teams

    New-CsOnlinePSTNGateway -Fqdn <Your Asterisk FQDN> -SipSignallingPort <Your Aterisk Port for TLS communication> -MaxConcurrentSessions <Max Concurrent Sessions the SBC/PBX can handle> -Enabled $true

    Example: New-CsOnlinePSTNGateway -Fqdn sipconnect.mydomain.com -SipSignallingPort 5061 -MaxConcurrentSessions 5 -Enabled $true

    These are the connection points for Direct Routing on Microsoft side (see here: https://docs.microsoft.com/de-de/microsoftteams/direct-routing-plan#sip-signaling-fqdns)

    • pstnhub.microsoft.com “Global FQDN“ must be tried first. When the SBC sends a request to resolve this name, the Microsoft Azure DNS servers return an IP address pointing to the primary Azure datacenter assigned to the SBC. The assignment is based on performance metrics of the datacenters and geographical proximity to the SBC. The IP address returned corresponds to the primary FQDN.
    • pstnhub.microsoft.com “ Secondary FQDN“ geographically maps to the second priority region.
    • pstnhub.microsoft.com “ Tertiary FQDN“ geographically maps to the third priority regionn

    These three FQDN's will resolve to these IP addresses:

    • 52.114.148.0
    • 52.114.132.46
    • 52.114.75.24
    • 52.114.76.76
    • 52.114.7.24
    • 52.114.14.70

    So you should open your firewall between these IP addresses and your asterisk machine (port MS teams source port 5061 and your asterisk destination port 5061 for signaling as well as 10000:20000 for voice)

    Configure MS Teams incoming call routing

    To configure the incoming call routing within MS Teams, you have to tell MS Teams, which user uses which PSTN number:

    Set-CsUser -Identity "<Diese E-Mail-Adresse ist vor Spambots geschützt! Zur Anzeige muss JavaScript eingeschaltet sein.>" -EnterpriseVoiceEnabled $true -HostedVoiceMail $true -OnPremLineURI tel:<your phone number in E.164 format (e.g. +491234567890)>

    Replace information within brackets "<>" with your data (removing the <>).

    Configure Teams outgoing call routing

    This topic is a little bit complex and is explained in more detail here: https://docs.microsoft.com/en-us/microsoftteams/direct-routing-configure#configure-voice-routing

    ATTENTION: This changes the call routing policy for ALL users!!!

    In short:

    1. Create a PSTN Usage
      Set-CsOnlinePstnUsage -Identity Global -Usage @{Add="All"}
      (Use Get-CsOnlinePstnUsage to check)
    2. Create Voice Route for all Calls
      New-CsOnlineVoiceRoute -Identity "All" -NumberPattern ".*" -OnlinePstnGatewayList <Your PBX FQDN> -Priority 0 -OnlinePstnUsages "All"
      (Use Get-CsOnlineVoiceRoute)

    3. Update Global Voice Routing Policy
      Set-CsOnlineVoiceRoutingPolicy "Global" -OnlinePstnUsages "All"
      (Use Get-CsOnlineVoiceRoutingPolicy to check)


    4. Assign Policy to user (user, you assigned the phone number, above)
      Grant-CsOnlineVoiceRoutingPolicy -Identity "<Diese E-Mail-Adresse ist vor Spambots geschützt! Zur Anzeige muss JavaScript eingeschaltet sein.>" -PolicyName "Global”
      (Use Get-CsOnlineUser -Identiy "<Diese E-Mail-Adresse ist vor Spambots geschützt! Zur Anzeige muss JavaScript eingeschaltet sein.>" to check. Search in the output for the line named "OnlineVoiceRoutingPolicy")

    Setup Asterisk configuration

    Add these sections to your /etc/asterisk/pjsip.conf
    A transport, which uses TLS, because MS Teams Direct Routing uses TLS:
    [transport-tls]
    type=transport
    protocol=tls
    bind=0.0.0.0:5061
    cert_file=/etc/asterisk/ssl/<your certificate file for the Asterisk FQDN>
    priv_key_file=/etc/asterisk/ssl/<your key file for the Asterisk FQDN>
    cipher=ECDHE-ECDSA-AES256-SHA,ECDHE-RSA-AES256-SHA,DHE-RSA-AES256-SHA,ECDHE-ECDSA-AES128-SHA,ECDHE-RSA-AES128-SHA,DHE-RSA-AES128-SHA,AES256-SHA,AES128-SHA
    method=tlsv1
    local_net=<your local net, e.g. 10.0.0.0/8>
    external_media_address=<External IP Address of your Asterisk>
    external_signaling_address=<External IP Address of your Asterisk>

    IMPORTANT: Create the /etc/asterisk/ssl directrory and change user and group to the user and group, the asterisk service runs under (e.g. asterisk:asterisk). Access rights: drwx------. Copy the certificate and key files for the Asterisk FQDN to that directory. The files have to have the same user and group as the directory and these access rights: -rw-r--r--

    An endpoint to route calls from the PSTN to MS Teams to:
    [msteams_trunk_out]
    type=endpoint
    transport=transport-tls
    disallow=all
    allow=ulaw,alaw,gsm
    aors = aor_msteams_trunk_out
    media_encryption=sdes
    from_domain=<Your PBX FQDN>
    [aor_msteams_trunk_out]
    type = aor
    qualify_frequency=60
    contact = sip:sip.pstnhub.microsoft.com
    An endpoint to catch calls to the PSTN, which have been originated in Microsoft Teams:
    [msteams_trunk_in]
    type = endpoint
    transport=transport-tls
    context = msteams_in
    disallow = all
    allow = ulaw, alaw, gsm
    media_encryption=sdes
    [ident_msteams_trunk_in]
    type=identify
    endpoint=msteams_trunk_in
    match=sip-all.pstnhub.microsoft.com

    (The "sip-all.pstnhub.microsoft.com' resolves to all IP addresses Microsoft uses for Direct Routing.)

    In the dialplan /etc/asterisk/extensions.conf

    Add a section to handle calls from Microsoft Teams to PSTN (here a sample with sipgate as destination endpoint):

    [msteams_in]
    ; to react on incoming SIP Options Packates with an "200 OK"

    exten => msteams_trunk_out,1,HangUp()

    exten => _[+X].,1,Noop(Processing outgoing call from MS Teams to PSTN)
    ; Following line is optional
    same => n,Set(CALLERID(num)=<your sender phone number in E.164 format (e.g. +4912345678)>)
    same => n,Dial(PJSIP/${EXTEN}@sipgate)
    same => n,HangUp()

    Here a sample to handle calls from sipgate (basic) to a MS Teams user:

    [sipgate-in]
    ; Handling sipgate.de related stuff
    exten => <your sipgate user id>,1,NoOp(Call via sipgate routing to s@incoming now)
    ; try to extract phone number from sip header P-Asserted-Identity
    same => n,Set(FON=$["${PJSIP_HEADER(read,P-Asserted-Identity)}" : "<sip:([0-9]+)"])
    same => n,ExecIf($[${ISNULL(${FON})}=0]?Set(CALLERID(num)=${FON}))
    ; save the MSN wich was dialed
    same => n,Set(CALLERID(dnid)=$[ "${PJSIP_HEADER(read,TO)}" : "<sip:([0-9e]+)" ])
    ; convert MSN to E.164 format for MS Teams
    same => n,Set(CALLERID(dnid)=+$[ "${CALLERID(dnid)}" : "00([0-9]+)" ])
    same => n,Goto(s,1)
    ;; Handle calls
    exten => s,1,Verbose(Route MSNs)
    same => n,GotoIf($["${CALLERID(dnid)}" = "<MSN1 in E.164 format (e.g. +4912345678)>"]?incoming-1,s,1)
    same => n,GotoIf($["${CALLERID(dnid)}" = "<MSN2 in E.164 format (e.g. +4912345679)>"]?incoming-2,s,1)
    same => n,Hangup
    [incoming-1]
    exten => s,1,NoOp(Route to <+4912345678> on MS Teams Trunk)
    same => n,Dial(PJSIP/${CALLERID(dnid)}@msteams_trunk)                Alternatively dial some other number, which is configured in MS Teams

    same => n,Hangup()

    [incoming-2]
    exten => s,1,NoOp(Route to <+4912345679> on MS Teams Trunk)
    same => n,Dial(PJSIP/${CALLERID(dnid)}@msteams_trunk)        Alternatively dial some other number, which is configured in MS Teams
    same => n,Hangup()

    The configuration might differ in details, depending on your environment, PSTN provider, etc..

    If things do not work, it's a good idea to debug SIP packets within Asterisk:

    Start asterisk console

    asterisk -rvvvv

    Switch on logging:

    pjsip set logger on

    core set debug 4

    Hope, this path helps you get through your MS Teams Direct Routing PBX connection.

    • Impressum
    • Datenschutz
    © ayonik GmbH. Alle Rechte vorbehalten.
    • Home
    • Projektmanagement
      • Überblick
      • Interim Projektmanager
      • Projekt Quick-Check
      • Projekt Audit
      • Projektsanierung
      • Risikomanagement
      • Download PM-Vorlagen
      • Projektabläufe optimieren
      • Unser Ansatz
    • Über uns
    • Blog