Asterisk17 + Ubuntuでさくっと内線電話網を構築する


# 初めに

SIPを使って内線電話が構築出来たら面白そうだなと思い、さっそく手元でやってみました。
この記事はその時の忘備録です。結果的にクラウド上に構築したSIPサーバーを使って、NAT環境下のAndroid2機間で内線通話を実現する事ができました。手順通り進められれば再現できるはずですが、何かあればコメントくださいませ

Ref: https://www.nic.ad.jp/ja/newsletter/No29/100.html

※本記事は入門記事です。本番環境の利用には想定していません。

# SIPサーバー構築手順

![20200308_Qiita-Page-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/128123/2ecb9842-6c41-6f7a-09a3-30f4cde35e26.png)
Fig. 今回構築するシステムの全体像

ネット上を探していると、Asteriskの古いバージョンでの入門記事だったり英語の記事がたくさんヒットします。英語ではありつつも本家マニュアルが結構参考になりました。

- 筆者環境
  - Ubuntu 16.04 (多分Ubuntu 18系でも大丈夫かと思われます)
  - さくらクラウド

参考にしたもの: https://wiki.asterisk.org/wiki/display/AST/Hello+World

## Asterisk17のビルド

ソースコードから落としてビルドします。
(apt経由でインストールする方法等がありましたが、筆者環境だと起動がうまくいきませんでした)

```
ubuntu@dev:~$ wget http://downloads.asterisk.org/pub/telephony/asterisk/asterisk-17.2.0.tar.gz
ubuntu@dev:~$tar -zxvf asterisk-17.2.0.tar.gz
ubuntu@dev:~$  cd asterisk-17.2.0/
ubuntu@dev:~$  ./contrib/scripts/install_prereq install
ubuntu@dev:~$ ./configure --with-jansson-bundled
ubuntu@dev:~$ ./make -j4
ubuntu@dev:~$ ./make install
ubuntu@dev:~$ ./make samples # 初期の設定ファイル等がインストールされる
```

## Asterisk17の設定

今回は内線電話番号6001,6002を構築し、お互いにつながるようにします。

### pjsip.confの設定

SIPサーバーに関する設定や内線電話（SIPクライアント）からの認証情報を設定します。

```conf:/etc/asterisk/pjsip.conf
[transport-udp]
type=transport
protocol=udp
bind=0.0.0.0

[6001]
type=endpoint
context=from-internal
disallow=all
allow=ulaw
auth=6001
aors=6001
rewrite_contact = yes # 6001がNAT環境下の場合、必要。

[6001]
type=auth
auth_type=userpass
password=unsecurepassword
username=6001

[6001]
type=aor
max_contacts=10

[6002]
type=endpoint
context=from-internal
disallow=all
allow=ulaw
auth=6002
aors=6002
rewrite_contact = yes # 6002がNAT環境下の場合、必要。

[6002]
type=auth
auth_type=userpass
password=unsecurepassword
username=6002

[6002]
type=aor
max_contacts=10
```

### extensions.conf

内線電話（SIPクライアント）からの発着信時のルールをここに記述します。

```conf:/etc/asterisk/extensions.conf
[from-internal]

exten = 100,1,Answer()
same = n,Wait(1)
same = n,Playback(hello-world)
same = n,Hangup()

# 6001がコールされたらSIPの6001を呼び出す
exten = 6001,1,Dial(PJSIP/6001,30,r)
same = n.Hangup()

# 6001がコールされたらSIPの6001を呼び出す

exten = 6002,1,Dial(PJSIP/6002,30,r)
same = n.Hangup()
```

## UFWの設定 (任意)

SIPサーバーを次のステップで起動しますが、起動してtcpdump等で見てみると、意外と
外国からの攻撃がすごいので、筆者環境ではUFWによるファイアウォールを入れました。
（必須ではないですが、入れておくと安心でしょう）

```shell-session
ubuntu@dev:~$ apt install ufw
ubuntu@dev:~$ ufw enable
ubuntu@dev:~$ ufw default DENY
# SIP用ポートを許可
ubuntu@dev:~$ ufw allow from XXX.XXX.XXX.XXX/32 to any port 5060 proto udp
# RTP用ポートを許可
ubuntu@dev:~$ ufw allow from XXX.XXX.XXX.XXX/32 to any port 10000:20000 proto udp
ubuntu@dev:~$ ufw reload
```

※`XXX.XXX.XXX.XXX`は、SIPクライアントとして接続が想定される元のIPです(SRCIP)

ref: https://qiita.com/yoh-nak/items/46935af3c5c4036e93b3

## Asterisk17のサービス起動

```shell-session
ubuntu@dev:~$ systemctl unmask asterisk
ubuntu@dev:~$ systemctl start asterisk
ubuntu@dev:~$ systemctl status asterisk
● asterisk.service - LSB: Asterisk PBX
   Loaded: loaded (/etc/init.d/asterisk; bad; vendor preset: enabled)
   Active: active (running) since Thu 2020-02-27 23:26:27 JST; 39min ago
     Docs: man:systemd-sysv-generator(8)
  Process: 1236 ExecStop=/etc/init.d/asterisk stop (code=exited, status=0/SUCCESS)
  Process: 1248 ExecStart=/etc/init.d/asterisk start (code=exited, status=0/SUCCESS)
 Main PID: 8328 (code=exited, status=0/SUCCESS)
    Tasks: 72
   Memory: 38.8M
      CPU: 19.957s
   CGroup: /system.slice/asterisk.service
           mq1261 /usr/sbin/asterisk

Feb 27 23:26:27 ootaguro-dev asterisk[1236]:    ...done.
Feb 27 23:26:27 ootaguro-dev systemd[1]: Stopped LSB: Asterisk PBX.
Feb 27 23:26:27 ootaguro-dev systemd[1]: Starting LSB: Asterisk PBX...
Feb 27 23:26:27 ootaguro-dev asterisk[1248]:  * Starting Asterisk PBX: asterisk
Feb 27 23:26:27 ootaguro-dev asterisk[1248]:    ...done.
Feb 27 23:26:27 ootaguro-dev systemd[1]: Started LSB: Asterisk PBX.
Feb 27 23:26:28 ootaguro-dev asterisk[1261]: rc_read_config: can't open /etc/radiusclient-ng/radiusclient.conf: No such file or directory
Feb 27 23:26:28 ootaguro-dev asterisk[1261]: rc_read_config: can't open /etc/radiusclient-ng/radiusclient.conf: No such file or directory
```

Radius関係のエラーがでますが、一旦無視しても後述のテストはPASSできます。
ERRORという文字が多く出る場合、モジュールのロードや設定に異常があるので確認したほうが良いです。

正常に起動すると、下記のようにSIPやIAXポートがLISTENされます。設定ファイルミスがある場合、`systemctl status asterisk`ではactive(running)表示でもLISTENできてないケースがあるので、チェックしておいた方が無難です。
（なんか予想以上に色々LISTENしているので別途調査しておいたほうがよさそうですね）

```shell-session
root@dev:/usr/src/asterisk-17.2.0# lsof -i | grep asterisk
asterisk  1261   root   10u  IPv4 10870690      0t0  UDP *:56066
asterisk  1261   root   11u  IPv6 10870691      0t0  UDP *:43403
asterisk  1261   root   12u  IPv4 10870678      0t0  UDP *:sip
asterisk  1261   root   20u  IPv4 10870696      0t0  UDP *:iax
asterisk  1261   root   21u  IPv4 10870700      0t0  UDP *:2727
asterisk  1261   root   22u  IPv4 10870704      0t0  TCP *:cisco-sccp (LISTEN)
asterisk  1261   root   25u  IPv4 10870717      0t0  UDP *:4520
asterisk  1261   root   26u  IPv4 10871862      0t0  UDP *:5000
```


# 実機テスト

今回は、Android端末を2台手元に用意し、Wifiルーターに接続させて実験しました。（NAT環境下）
ゴールは、SIPクライアントとして動作させる2台のAndroid端末間で内線電話の発着信＆通話ができる事です。

## MizuDroidのインストール

PlayStoreからSIPクライアントであるMizudroidを2台のAndroid端末に導入します。
iPhoneの場合もいくつか、SIPクライアントがAppleStoreにあるようです。
(GoogleログインしたPCでアクセスすると、リモートでいストールが実行できる模様）

https://play.google.com/store/apps/details?id=com.mizuvoip.mizudroid.app&hl=ja

<img width="300px" alt="Screenshot_20200228-000727.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/128123/4a47e8a2-db8a-af68-8518-c51890e0a7b5.png">

## MizuDroidにSIPサーバーの情報を入力

<img width="300px" alt="Screenshot_20200227-235340.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/128123/2d6ef670-3bdd-01a9-9e87-6a69821b5be4.png">

上記の画像では、内線番号6001の認証情報を入力しました。内線番号6001と6002のそれぞれの認証情報を2台のアプリ設定に入れ込みます。正しく認証されると、REGISTEREDという緑色の文字が見れます。Failという文字が出てくる場合は、入力した認証設定が間違えている可能性があります。

## 内線番号6001 → 内線番号6002への発信

<img width="300px" alt="Screenshot_20200228-001344.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/128123/70004dcf-f879-d761-3ac4-e9e6a500d009.png">

ここまでの設定がうまくいっていれば、もう片方の携帯(内線番号6002に設定)が着信するはずです。
バックグラウンドで動作させないとアプリがフォアグラウンドにいる時しか着信できないので注意しましょう。

# 余談: TCPDUMPでのパケットキャプチャ

自分自身のSIP理解の為に、やり取りされているパケットを実際に覗いてみました。

## 認証時の様子 (アプリ立ち上げ時)

サーバーに向かってREGISTERが飛んできている。Digest認証を用いている模様。
それに対して200OKが返却されている。意外とHTTPと似たようなプロトコルの作りっぽい。

XXX.XXX.XXX.XXX => SIPクライアント(MIZUDROID)のGIP (NAT環境なので出口のIP)
YYY.YYY.YYY.YYY => SIPサーバー(Asterisk)のGIP

```
ubuntu@dev:~$  sudo tcpdump -vni any -s0 port 5060
23:45:24.698632 IP (tos 0x0, ttl 51, id 47054, offset 0, flags [DF], proto UDP (17), length 914)
    XXX.XXX.XXX.XXX.14425 > YYY.YYY.YYY.YYY.5060: SIP, length: 886
        REGISTER sip:YYY.YYY.YYY.YYY:5060 SIP/2.0
        Via: SIP/2.0/UDP XXX.XXX.XXX.XXX:10784;rport;branch=z9hG4bK-49p4241941521357628102r
        From: <sip:6002@YYY.YYY.YYY.YYY>;tag=48g693852704041038639m
        To: <sip:6002@YYY.YYY.YYY.YYY>
        Call-ID: 46e2593884576040101175k8434rmwp
        CSeq: 7250 REGISTER
        Max-Forwards: 70
        Expires: 180
        Authorization: Digest username="6002",realm="asterisk",nonce="1582814724/1b2032af1c4a73529219052df1e041d7",uri="sip:YYY.YYY.YYY.YYY:5060",response="ed22cb18e22c2a1c81e8e0bba7ea6fac",opaque="7b404df425a56bb0",cnonce="6228548815293381558",nc=00000001,qop=auth,algorithm=MD5
        Contact: <sip:6002@XXX.XXX.XXX.XXX:10784>
        X-UT: a
        User-Agent: MizuDroid/2.7.0
        X-DeviceID: d559a947758b1856
        Supported: replaces
        Allow: ACK,PRACK,BYE,CANCEL,INVITE,UPDATE,MESSAGE,INFO,OPTIONS,SUBSCRIBE,NOTIFY,REFER
        Accept: application/sdp,application/dtmf-relay,text/plain
        Content-Length: 0

23:45:24.701050 IP (tos 0x0, ttl 64, id 30505, offset 0, flags [DF], proto UDP (17), length 558)
    YYY.YYY.YYY.YYY.5060 > XXX.XXX.XXX.XXX.14425: SIP, length: 530
        SIP/2.0 200 OK
        Via: SIP/2.0/UDP XXX.XXX.XXX.XXX:10784;rport=14425;received=XXX.XXX.XXX.XXX;branch=z9hG4bK-49p4241941521357628102r
        Call-ID: 46e2593884576040101175k8434rmwp
        From: <sip:6002@YYY.YYY.YYY.YYY>;tag=48g693852704041038639m
        To: <sip:6002@YYY.YYY.YYY.YYY>;tag=z9hG4bK-49p4241941521357628102r
        CSeq: 7250 REGISTER
        Date: Thu, 27 Feb 2020 14:45:24 GMT
        Contact: <sip:6002@XXX.XXX.XXX.XXX:9663>;expires=23
        Contact: <sip:6002@XXX.XXX.XXX.XXX:14425>;expires=179
        Expires: 180
        Server: Asterisk PBX 17.2.0
        Content-Length:  0
```

# まとめ

今回、SIPサーバーを構築し、SIPクライアントを導入したAndroid端末間で内線通話をする事ができました。
今後の展望としては、下記の記事のようにTwilioと連携させてPSTN(電話回線網）と発着信したりチャレンジできればと思っています。
https://qiita.com/sgrowd/items/dd1fc682718a2a623e4c

次記事：https://qiita.com/xecus/items/a5e677bb85372e502b37 (追記)


ありがとうございました。