Microsoft TeamsとAsteriskを接続する

# 前提条件

- Microsoft Teamsが有効なMicrosoft 365アカウント
    - Microsoft 電話システムのライセンスが必要
    - example.onmicrosoft.comのようなドメインではなく、独自ドメインを利用している必要あり
    - 例：example.com
- Asterisk 18.9.0
    - TLS/SRTPが有効になっていること
- Asteriskが動作しているホストのIPアドレスが引けるホスト名があること
    - 例：sbc01.example.com(このドメインはMicrosoft 365で利用しているドメインと一致している必要あり)
- SSL証明書(例：sbc01.example.com)
    - [ダイレクト ルーティングを計画する - SBC 用の公開された信頼できる証明書 - Microsoft](https://docs.microsoft.com/ja-jp/microsoftteams/direct-routing-plan#public-trusted-certificate-for-the-sbc)に記載されているルート証明機関である必要あり
    - 2022/8/20 現在は、Let's Encryptionの証明書のルート証明機関も含まれている(ISRG Root X1)

当然ながら、Microsoftの認定を受けたSBCでは無いため、試すときは自己責任でお願いします。

# 設定(Microsoft 365側)

- 別の記事にまとめていますので、そちらを参照してください
- [Microsoft Teamsでダイレクトルーティングを構成する](https://qiita.com/tatsuya_info/items/23825e98d2a3cb6443ba)

# 事前準備(Asterisk側)

Microsoft 365側からSBC(今回の場合、Asterisk)の死活監視をするためにSIPのOPTIONSメソッドを利用しているのですが、ContactヘッダーにSBCのFQDNが埋め込まれている必要があります。
AsteriskはFQDNを正引きした?、IPアドレスを埋め込むため、そのままでは使えません。

次のようにソースコードを書き換えて、コンパイルします。
※ \<SBC FQDN\>を書き換えてください。

* Asterisk 20系も同じようにパッチを当てる必要あり

```
--- work/asterisk-16.10.0/res/res_pjsip_nat.c.orig	2020-05-07 19:14:57.852024000 +0900
+++ work/asterisk-16.10.0/res/res_pjsip_nat.c	2020-05-07 19:15:37.585243000 +0900
@@ -409,7 +409,7 @@
	if (!ast_sockaddr_isnull(&transport_state->external_signaling_address)) {
		/* Update the contact header with the external address */
		if (uri || (uri = nat_get_contact_sip_uri(tdata))) {
-			pj_strdup2(tdata->pool, &uri->host, ast_sockaddr_stringify_host(&transport_state->external_signaling_address));
+			pj_strdup2(tdata->pool, &uri->host, "<SBC FQDN>");
			if (transport->external_signaling_port) {
				uri->port = transport->external_signaling_port;
				ast_debug(4, "Re-wrote Contact URI port to %d\n", uri->port);
@@ -418,7 +418,7 @@

		/* Update the via header if relevant */
		if ((tdata->msg->type == PJSIP_REQUEST_MSG) && (via || (via = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL)))) {
-			pj_strdup2(tdata->pool, &via->sent_by.host, ast_sockaddr_stringify_host(&transport_state->external_signaling_address));
+			pj_strdup2(tdata->pool, &via->sent_by.host, "<SBC FQDN>");
			if (transport->external_signaling_port) {
				via->sent_by.port = transport->external_signaling_port;
			}
```


# 設定(Asterisk側)

既存システムと繋ぐ部分は省いてます。

```pjsip.conf
[transport-tls]
type=transport
protocol=tls
bind=0.0.0.0:5061
; NAT配下の場合
;external_media_address=xx.xx.xx.xx
;external_signaling_address=xx.xx.xx.xx
cert_file=/usr/local/etc/ssl/o365.crt
priv_key_file=/usr/local/etc/ssl/o365.key
method=tlsv1

[msteams_trunk_out]
type = endpoint
transport = transport-tls
disallow = all
allow = ulaw
aors = aor_msteams_trunk_out
media_encryption = sdes
from_domain = <SBC FQDN>

[aor_msteams_trunk_out]
type = aor
qualify_frequency=60
contact = sip:sip.pstnhub.microsoft.com

[msteams_trunk_in]
type = endpoint
transport=transport-tls
context = default
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
```

```extensions.conf
[general]
;static=yes
writeprotect=yes
autofallthrough=yes

[default]
; Life Check
exten => msteams_trunk_out,1,HangUp()

; Teams ->
exten => _+81.,1,Dial(IAX2/peer/${EXTEN})

; -> Teams
exten => _9.,1,Set(CALLERID(num)=+81...)
exten => _9.,n,Dial(PJSIP/+81${EXTEN}@msteams_trunk_out)
```

# パケットフィルタ

Asteriskは割と攻撃されやすい気がするので、SIPのシグナリングパケットを制限します。

MicrosoftのドキュメントにFQDNやアドレスレンジは記載されているので、これを参考にするだけです。
- [ダイレクト ルーティングを計画する - SIP シグナル: FQDN](https://docs.microsoft.com/ja-jp/microsoftteams/direct-routing-plan#sip-signaling-fqdns)

FreeBSDのpfだとこんな感じ。アドレスレンジは2021/6/30現在

```/etc/pf.conf
ext_if="vtnet0"

pass in quick on $ext_if proto tcp from 52.112.0.0/14 to ($ext_if) port SIGNALPORT
pass in quick on $ext_if proto tcp from 52.120.0.0/14 to ($ext_if) port SIGNALPORT
block in quick on $ext_if proto tcp from any to ($ext_if) port SIGNALPORT
```

# 参考にしたサイト

- [Proof of Concept: Connecting Microsoft Teams via Direct Routing with an Asterisk PBX - ayonik.de](https://ayonik.de/blog/item/90-microsoft-teams-direct-routing-with-asterisk-pbx)
    - ほぼこのサイトの受け売りです。
- [Microsoft Teams, Direct Routing and Asterisk running on a Raspberry Pi 4. - FULLY'S BLOG](https://afullagar.wordpress.com/2019/12/04/microsoft-teams-direct-routing-and-asterisk-running-on-a-raspberry-pi-4/)
    - 本記事と同じことをRPi4でやってる人
- [OpenSIPS as MS Teams SBC](https://blog.opensips.org/2019/09/16/opensips-as-ms-teams-sbc/)
    - OpenSIPSだと、Asteriskみたいにコンパイルし直さなくても、Contactヘッダーに任意のFQDN埋め込めるみたいだけど、Asteriskユーザからすると、設定が難解すぎて諦めました。
    - 別記事でopenSIPSとTeams繋げました
    - [Microsoft TeamsとopenSIPSを接続する
](https://qiita.com/tatsuya_info/items/4406e1515cd77a273a6d)