2019Nov05

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.

 

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 cannot not 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.
  • 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
    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

    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.

 

 

Artikel bewerten
(14 Stimmen)