OpenSIPS as MS Teams SBC

Microsoft Teams

Microsoft Teams is the product which is going to replace Lync and Skype for Business. With MS Teams you can communicate with users on your Office365 tenant. It is straightforward in case you don’t need to talk to people outside of your company. And in case you do need connection to the outside world there are 2 ways:

  • buy phone numbers and outgoing traffic from Microsoft
  • use so called “Direct Routing” to connect over SIP.

How can OpenSIPS help?

Most of companies already have some infrastructure with employee’s phones, external phone numbers, which are known to customers etc. So, MS Teams Direct Routing is the way to connect MS Teams infrastructure and the existing telephony infrastructure of the company. With proper configuration external numbers can be forwarded to MS Teams or left on PBX, and existing outgoing trunks can be used for calling out from MS Teams.

OpenSIPS can process SIP very efficiently, so why not to use it instead of Microsoft certified Session Border Controllers.

MS Teams doesn’t use user/password authentication, that’s why it has some very specific requirements for SIP to authenticate and authorize calls. Let’s start with the very simple case, with just one MS Teams tenant for one company.

MS Teams encrypts all the traffic. SBC should use SIP over TLS and SRTP for media. SRTP processing is the responsibility of a media server or RTPEngine. Of course, our SBC should have a correct FQDN (let’s call it SBC_FQDN) and an SSL certificate for this name. For this article we created a domain “voipgw.ipnordic.dk”. While configuring MS Teams part we should add exactly this domain SBC_FQDN to Office365 tenant and add Direct Routing SBC with Power Shell.

Configuring Direct Routing in MS Teams

Microsoft provides documentation on the setup of Direct Routing for Teams. So, this article describes very basic steps for adding the Direct Routing gateway.

Add domain SBC_FQDN (voipgw.ipnordic.dk) to Office365 tenant:

If you login to administration interface for MS Teams and choose Voice ->Direct Routing, there will be nothing:

Before you add Direct Routing SBC to MS Teams, you should add a user to the new domain “voipgw.ipnordic.dk”:

Now it is possible to add gateway with PowerShell. First connect with our Microsoft credentials:

PS> $userCredential = Get-Credential
PS> $sfbSession = New-CsOnlineSession -Credential $userCredential
PS> Import-PSSession $sfbSession

Then add the Direct Routing gateway:

PS> New-CsOnlinePSTNGateway -Fqdn voipgw.ipnordic.dk -SipSignallingPort 5061 
-MaxConcurrentSessions 10 -ForwardCallHistory $true -Enabled $true

So finally you should get the successful result:

Identity                          : voipgw.ipnordic.dk
Fqdn                              : voipgw.ipnordic.dk 
SipSignallingPort                 : 5061
FailoverTimeSeconds               : 10
ForwardCallHistory                : True
ForwardPai                        : False
SendSipOptions                    : True
MaxConcurrentSessions             : 10
Enabled                           : True
MediaBypass                       : False
GatewaySiteId                     :
GatewaySiteLbrEnabled             : False
FailoverResponseCodes             : 408,503,504
GenerateRingingWhileLocatingUser  : True
PidfLoSupported                   : False
MediaRelayRoutingLocationOverride :
ProxySbc                          :
BypassMode                        : None

Configuring OpenSIPS

Now it’s time to also configure OpenSIPS, to accept the calls from MS Teams and to route it further. First, the simple TLS configuration:

listen=tls:WAN_IP:5061 loadmodule "tls_mgm.so"
modparam("tls_mgm","verify_cert", "1")
modparam("tls_mgm","require_cert", "1")
modparam("tls_mgm","tls_method", "TLSv1_2")
modparam("tls_mgm","certificate", "/etc/tls/dom1/fullchain.pem")
modparam("tls_mgm","private_key", "/etc/tls/dom1/privkey.pem")
modparam("tls_mgm", "ca_list", "/etc/ssl/certs/ca-bundle.crt")

OpenSIPS will verify client TLS certificates, e.g. connections from Microsoft servers. The certificate authorities list depends on the operating system. The path in the example is for CentOS 7.

Microsoft requires that a client SBC sends SIP OPTIONS requests. Otherwise the SBC will be considered as “Inactive” and Microsoft will ignore any traffic coming from the SBC.

OPTIONS request for MS Teams must contain the Contact header of such a format:

Contact: <sip:SBC_FQDN:5061;transport=tls>

In RFC3261 we can find, that Contact header MAY be present in an OPTIONS request, so that Microsoft requirements don’t conflict with the RFC. To send periodic OPTIONS we can use an external script or any of modules with pinging/probing gateways features. For example, let’s take a standard configuration with Dynamic Routing module. Let’s add all three Microsoft entry points as dynamic routing gateways and specify in the database tls sockets for probing.

gwidaddressprobe_modestatesocket
ms1sip.pstnhub.microsoft.com20tls:<SBC_WAN_IP>:5061
ms2sip2.pstnhub.microsoft.com20tls:<SBC_WAN_IP>:5061
ms3sip3.pstnhub.microsoft.com20tls:<SBC_WAN_IP>:5061

Now we can see, that OpenSIPS tries to connect to MS Teams:

INFO:proto_tls:tls_connect: New TLS connection to 52.114.76.76:5061 established
INFO:proto_tls:tls_dump_cert_info: tls_connect: server TLS certificate subject: /CN=sip.pstnhub.microsoft.com,
issuer: /C=US/ST=Washington/L=Redmond/O=Microsoft Corporation/OU=Microsoft IT/CN=Microsoft IT TLS CA 4

But standard modules don’t add the Contact header to OPTIONS, because it is not required by RFC, so we need to add it from the configuration script:

local_route {
  $var(dst) = "pstnhub.microsoft.com";
  if (is_method("OPTIONS") && ($(ru{s.index, $var(dst)}) != NULL))
    append_hf("Contact: <sip:SBC_FQDN:5061;transport=tls>\r\n");
}

Now we get some responses from MS Teams, but with default settings in OpenSIPS there will be different errors during a TLS handshake:

ERROR:core:tcp_connect_blocking_timeout: connect timed out, 99219 us elapsed out of 100000 us
ERROR:proto_tls:tls_sync_connect: tcp_blocking_connect failed
ERROR:proto_tls:proto_tls_send: connect failed ERROR:tm:msg_send: send() to 52.114.148.0:5061 for proto tls/3 failed
ERROR:tm:t_uac: attempt to send to 'sip:sip.pstnhub.microsoft.com' failed

Logs show that the default timeout for connection is too small. We should increase it:

modparam("tls_mgm", "tls_handshake_timeout", 300)

However even after that the same errors are still left in logs. This is because TLS uses tcp for connection, so tcp connection timeout should be increased too, this is a global parameter:

tcp_connect_timeout=300

Now we send correct OPTIONS request to MS Teams. We should process OPTIONS from them. Check IP-addresses of source with the permissions module table:

# Checks from MS Teams
if(is_method("OPTIONS") && is_domain_local("$rd") && check_source_address("2")) {
  xlog("L_INFO", "[MS TEAMS] OPTIONS In");
  send_reply("200", "OK");
  exit;
}

Packets with all certificates are long, so the maximum number of fragments, which can contain SIP message over TLS should be increased

modparam("proto_tls", "tls_max_msg_chunks", 8)

Finally, we can see on the MS Teams admin portal, that the new SBC has the “TLS connectivity status” and the “SIP options status” Active:

Making calls

So, we can call from MS Teams to outside. Just remember to use SRTP for media on your side.

Then we can just route calls with dynamic routing to MS Teams. And can try to call to users of MS Teams, but Microsoft doesn’t allow:

SIP/2.0 403 Forbidden
FROM: "ipnordic"<sip:+4589102030@10.20.0.133>;tag=rcDtpcp16r6Bg
TO: <sip:4583008300@10.20.0.132>
CSEQ: 6526398 INVITE
CALL-ID: fc6c053a-1838-1238-b3ae-1eea2439faf6
VIA: SIP/2.0/UDP 10.20.0.133:5080;received=10.20.0.133;branch=z9hG4bKmj7Zmt2gjtaBm;rport=5080
REASON: Q.850;cause=21;text="e7646e44-e4ef-473e-b0b5-cc8efb416634;Provided Trunk FQDN '185.46.45.202' is not allowed. Connection allows following fqdns: voipgw.ipnordic.dk, voipgw.ipnordic.dk."
CONTENT-LENGTH: 0
ALLOW: INVITE
ALLOW: ACK
ALLOW: OPTIONS
ALLOW: CANCEL
ALLOW: BYE
ALLOW: NOTIFY
SERVER: Microsoft.PSTNHub.SIPProxy v.2019.4.24.4 i.EUNO.3

This is actually the second and the last requirement. It doesn’t matter, what domain names in the “To” and “From” headers are, INVITE must contain Route header with SBC_FQDN, not just IP address. No problem for OpenSIPS:

record_route_preset("SBC_FQDN:5061;transport=tls", "LAN_IP:5060");
add_rr_param(";r2=on");

And that’s it, calls can successfully come to the MS Teams client on the desktop:

And an administrator of MS Teams can see stats for SBC:

OpenSIPS is configured as Microsoft Teams Direct Routing SBC. Now there are a lot of possibilities to improve this setup. SBC should be reliable, just put another OpenSIPS and make a cluster.

And OpenSIPS has a feature which doesn’t exist in any commercial SBC for Teams. It can support multiple SIP over TLS connection for MS Teams with different certificates.

So, using OpenSIPS as SBC for MS Teams has unlimited possibilities for further integration.

3 thoughts on “OpenSIPS as MS Teams SBC

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s