1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Microsoft TeamsとopenSIPSを接続する

Last updated at Posted at 2022-08-20

前提条件

  • Microsoft Teamsが有効なMicrosoft 365アカウント
    • Microsoft 電話システムのライセンスが必要
    • example.onmicrosoft.comのようなドメインではなく、独自ドメインを利用している必要あり
    • 例:example.com
  • openSIPS 3.3
    • 標準モジュールに追加でdomain/permissions/TLS(proto_tls, tls_openssl,tls_mgm)/droutingが有効になっていること
  • openSIPSが動作しているホストのIPアドレスが引けるホスト名があること
    • 例:sbc1.example.com(このドメインはMicrosoft 365で利用しているドメインと一致している必要あり)
  • SSL証明書(例:sbc1.example.com)

当然ながら、Microsoftの認定を受けたSBCでは無いため、試すときは自己責任でお願いします。
別記事で、AsteriskとTeamsを繋げてますが、Asteriskはソースコードの書き換えが必要で、毎回手間なので
openSIPSで試してみました。始めてopenSIPSを使っているので、本当にとりあえず動いているレベルです。

設定(Microsoft 365側)

別記事にまとめていますので、そちらを参照してください

事前準備(openSIPS側)

openSIPSを導入しておきます。

openSIPSは設定ファイルと別に構成情報を保存するデータベースが必須のようです。
(とりあえず、MySQLで動くことは確認済みで、時間が有ったらSQLiteで試したい)

設定(openSIPS側)

既存システムともTLSで接続をしているので、そのあたりは適当に読み替えてください。

opensips.cfg
## UDPソケットは使わないのでコメントアウトします。(既存システムと繋ぐときに使う残す)
#socket=udp:127.0.0.1:5060   # CUSTOMIZE ME
## 同様に proto_udp のモジュールもコメントアウトします。
#loadmodule "proto_udp.so"

## TLSソケットを開ける 下記はプライベートIPアドレスだけど、NAT越えは面倒なのでグローバル前提
socket=tls:192.168.0.1:5061

### 各種モジュール
## データベースにMySQLを使う
loadmodule "db_mysql.so"
## domainモジュール(リクエストが自分のSIPドメインかチェック)
loadmodule "domain.so"
modparam("domain", "db_url", "mysql://dbuser:dbpass@localhost/opensips")

## permissionモジュール(ACL関係)
loadmodule "permissions.so"
modparam("permissions", "db_url", "mysql://dbuser:dbpass@localhost/opensips")

## drouting(dynamic routing)
loadmodule "drouting.so"
modparam("drouting", "db_url","mysql://dbuser:dbpass@localhost/opensips")

## TLS関係
loadmodule "proto_tls.so"
# この辺は細かく調整してない
modparam("proto_tls", "tls_handshake_timeout", 1000)
modparam("proto_tls", "tls_send_timeout", 1000)
modparam("proto_tls", "tls_max_msg_chunks", 8)

loadmodule "tls_openssl.so"

loadmodule "tls_mgm.so"
# server_domain/client_domainのあたりもよく理解してない
# verify_certを1にすると上手く動かない
modparam("tls_mgm","server_domain", "sbc1.example.com")
modparam("tls_mgm","match_ip_address", "[sbc1.example.com]*")
modparam("tls_mgm","verify_cert", "[sbc1.example.com]0")
modparam("tls_mgm","require_cert", "[sbc1.example.com]0")
modparam("tls_mgm","tls_method", "[sbc1.example.com]TLSv1_2")
modparam("tls_mgm","certificate", "[sbc1.example.com]/etc/letsencrypt/live/sbc1.example.com/cert.pem")
modparam("tls_mgm","private_key", "[sbc1.example.com]/etc/letsencrypt/live/sbc1.example.com/privkey.pem")
modparam("tls_mgm","ca_list", "[sbc1.example.com]/etc/letsencrypt/live/sbc1.example.com/fullchain.pem")
modparam("tls_mgm", "ca_dir", "[sbc1.example.com]/etc/ssl/certs/")

modparam("tls_mgm", "client_domain", "defaultdom")
modparam("tls_mgm", "match_ip_address", "[defaultdom]*")
modparam("tls_mgm", "match_sip_domain", "[defaultdom]*")
modparam("tls_mgm", "verify_cert", "[defaultdom]0")
modparam("tls_mgm", "require_cert", "[defaultdom]0")
modparam("tls_mgm", "tls_method", "[defaultdom]tlsv1_2")
modparam("tls_mgm", "certificate", "[defaultdom]/etc/letsencrypt/live/sbc1.example.com/cert.pem")
modparam("tls_mgm", "private_key", "[defaultdom]/etc/letsencrypt/live/sbc1.example.com/privkey.pem")
modparam("tls_mgm","ca_list", "[defaultdom]/etc/letsencrypt/live/sbc1.example.com/fullchain.pem")
modparam("tls_mgm", "ca_dir", "[defaultdom]/etc/ssl/certs/")

## 「route {」の上に追加した
## Teamsから送信されるOPTIONメッセージの返答に必要なContactヘッダーを追加
##「($(ru{s.index, $var(dst)}) != NULL)」の部分の調査必要
local_route {
  $var(dst) = "pstnhub.microsoft.com";
  if (is_method("OPTIONS") && ($(ru{s.index, $var(dst)}) != NULL))
    append_hf("Contact: <sip:sbc1.example.com:5061;transport=tls>\r\n");
}

## 「route {」の中に追記・「if (has_totag()) {」の前
## Teamsから送信されるOPTIONメッセージへ200 OKで返す
## check_source_addressの中の2は後で出てくる、addressテーブルのgrpと紐付いてる
	# Checks from MS Teams
	if(is_method("OPTIONS") && is_domain_local("$rd") && check_source_address(2)) {
	  xlog("L_INFO", "[MS TEAMS] OPTIONS In\r\n");
	  send_reply(200, "OK");
	  exit;
	}

## 「	# record routing」の下
	if (!is_method("REGISTER|MESSAGE")){
# 初期値 コメントアウト
#		record_route();

		# 多分この書き方だと、Teams以外に影響ありそう(専用ならいいんだけろうけど)
		record_route_preset("sbc1.example.com:5061;transport=tls");
	}

##「	# do lookup with method filtering」の前
# これもいまいちだけど、とりあえずTeamsからはE.164形式で飛んでくるので、それと一致したらTeams関係とする
	if ($rU=~"^\+[0-9]+") {
	  xlog("L_INFO", "[LOGGER] INVITE\r\n");

		if (!is_from_local()) {
			# ローカル宛でないのは処理しない 403で返す
			send_reply(403,"Forbidden access to media service");
			exit;
		}else if(check_source_address(2)){
			# ソースアドレスチェックし、グループ2(Teams側)だったら既存にRelay
			xlog("L_INFO", "[LOGGER] FROM TEAMS\r\n");
			t_relay(2,"tls:relay-to-sip-proxy.example.com:5061");
			exit;
		}else if(check_source_address(1)){
			# ソースアドレスチェックし、グループ1(既存側)だったらContactヘッダー追加してTeamsにRelay
			xlog("L_INFO", "[LOGGER] FROM LOCAL\r\n");
			append_hf("Contact: <sip:sbc1.example.com:5061;transport=tls>\r\n");
			 t_relay(2,"tls:sip.pstnhub.microsoft.com:5061");
			 exit;
		}
	}

データベースに登録が必要なレコード

とりあえず、MySQLのクエリのまま

## drouting関係(Teams側でOPTIONメッセージによるSBC監視を行うため)
## 最後のパラメタはListenに書いた内容と合わせる
insert into dr_gateways (gwid,address,probe_mode,state,socket) VALUES ('ms1','sip.pstnhub.microsoft.com',2,0,'tls:192.168.0.1:5061');
insert into dr_gateways (gwid,address,probe_mode,state,socket) VALUES ('ms2','sip2.pstnhub.microsoft.com',2,0,'tls:192.168.0.1:5061');
insert into dr_gateways (gwid,address,probe_mode,state,socket) VALUES ('ms3','sip3.pstnhub.microsoft.com',2,0,'tls:192.168.0.1:5061');

## ACL 既存システム側
insert into address set grp=1, ip='192.168.2.1'
## ACL Teams側(実際は下記URLを参照し登録するサブネット確認してください)
## https://docs.microsoft.com/ja-jp/microsoftteams/direct-routing-plan#sip-signaling-fqdns
insert into address set grp=2, ip='52.112.0.0', mask=14;
insert into address set grp=2, ip='52.120.0.0', mask=14;

## 自分が処理すべきSIPドメイン
## Teams側
insert into domain set domain='sip.pstnhub.microsoft.com';
## 既存側
insert into domain set domain='sbc1.example.com';

パケットフィルタ

ここも、Asteriskで接続している記事を参照してください。

ただ、openSIPSはRTP中継しないのでSIPだけ開ければ大丈夫です。

参考にしたサイト

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?